css
1. 两个嵌套div,外层div宽度500px,内层div宽度20%,要求把内层div设置成正方形
<div class="outer">
<div class="inner"></div>
</div>
.outer {
width: 500px; /*0 外层 div 宽度固定为 500px */
height: auto; /*0 可以根据内容自动调整高度 */
background-color: lightgray; /*0 用于区分外层 div */
}
.inner {
width: 20%; /* 内层 div 宽度为外层的 20% */
padding-top: 20%; /* 通过 padding-top 来设置高度为宽度的 100%,即实现正方形 */
background-color: lightblue; /*0 用于区分内层 div */
}
/*
高度的实现 通过 padding-top: 20%,这是因为在 CSS 中,padding-top 是相对于宽度计算的,
因此设置 padding-top 为 20% 会使得高度和宽度相等,从而实现正方形效果。
*/
2. 一个div嵌套三个div 外层div为flex布局,实现内层俩个div靠左 第三个div靠右
<div class="outer">
<div class="left1">Left 1</div>
<div class="left2">Left 2</div>
<div class="right">Right</div>
</div>
.outer {
display: flex; /* 设置外层 div 为 flex 布局 */
}
.right {
margin-left: auto; /* 将右侧的 div 推到最右边 */
}
3. 用 css 实现如下的多列布局(类似九宫格,右下角为空)效果:父元素宽度自适应所在容器宽度,高度由子元素撑开, 有不定数量的直接子元素(可以用8个演示),每一行排3 个子元素,子元素之间的水平、垂直间距为 10px ,子元素的宽度自适应父元素的宽度((父元素宽度 - 10px * 2) / 3),子元素的高度与自身的宽度成正比(比如 2:1)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>九宫格布局</title>
<style>
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 三列 */
gap: 10px; /* 间距 */
/* width: 300px; 父元素宽度 */
margin: 0 auto; /* 居中 */
}
.item {
background-color: #69c; /* 子元素背景色 */
border: 1px solid #000;
aspect-ratio: 1 / 2; /* 宽度与高度比例为1:2 */
}
/* 去掉右下角 */
/* .item:nth-child(9) {
display: none;
} */
</style>
</head>
<body>
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<!-- <div class="item">9</div> -->
<!-- 第九个元素为空 -->
</div>
</body>
</html>
4.画一个表盘,实现分针和秒钟的旋转动画
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表盘动画</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="clock">
<div class="dial">
<div class="hand second-hand"></div>
<div class="hand minute-hand"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
/* styles.css */
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: #f5f5f5;
}
.clock {
width: 200px;
height: 200px;
border: 8px solid #333;
border-radius: 50%;
position: relative;
background: white;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
}
.dial {
position: relative;
width: 100%;
height: 100%;
}
.hand {
position: absolute;
bottom: 50%;
left: 50%;
transform-origin: bottom;
transform: rotate(0deg);
transition: transform 0.1s ease-in-out;
}
.second-hand {
width: 2px;
height: 90px;
background: red;
z-index: 2;
}
.minute-hand {
width: 4px;
height: 70px;
background: black;
z-index: 1;
}
// script.js
function setClock() {
const now = new Date();
// 计算当前秒和分的角度
const seconds = now.getSeconds();
const minutes = now.getMinutes();
const secondDegree = (seconds / 60) * 360;
const minuteDegree = (minutes / 60) * 360 + (seconds / 60) * 6; // 添加秒钟影响
// 更新样式
const secondHand = document.querySelector('.second-hand');
const minuteHand = document.querySelector('.minute-hand');
secondHand.style.transform = `rotate(${secondDegree}deg)`;
minuteHand.style.transform = `rotate(${minuteDegree}deg)`;
}
// 每秒更新一次
setInterval(setClock, 1000);
// 初始设置
setClock();
react
1. 编写一个倒计时ui组件 组件有俩个参数:截止时间deadline和时间到期时执行的回调函数cb
import React, { useEffect, useState } from 'react';
const Countdown = ({ deadline, cb }) => {
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft(deadline));
// 计算剩余时间的函数
function calculateTimeLeft(deadline) {
const difference = new Date(deadline) - new Date();
if (difference > 0) {
return {
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / 1000 / 60) % 60),
seconds: Math.floor((difference / 1000) % 60),
};
} else {
return null; // 如果时间到了,返回null
}
}
// 倒计时更新逻辑
useEffect(() => {
const timer = setInterval(() => {
const newTimeLeft = calculateTimeLeft(deadline);
setTimeLeft(newTimeLeft);
if (!newTimeLeft) {
clearInterval(timer); // 清除计时器
if (cb) cb(); // 执行回调函数
}
}, 1000);
return () => clearInterval(timer); // 清除副作用
}, [deadline, cb]);
// 倒计时的 UI 展示
return (
<div>
{timeLeft ? (
<div>
<span>{timeLeft.hours}h </span>
<span>{timeLeft.minutes}m </span>
<span>{timeLeft.seconds}s</span>
</div>
) : (
<div>Time's up!</div>
)}
</div>
);
};
export default Countdown;
2.实现useFetch
import { useState, useEffect, useCallback } from 'react';
function useFetch(url, options = {}) {
const [data, setData] = useState(null); // 存储请求的数据
const [loading, setLoading] = useState(true); // 请求状态:加载中
const [error, setError] = useState(null); // 存储错误信息
const [shouldFetch, setShouldFetch] = useState(true); // 控制是否进行请求
// fetchData 用于发起请求
const fetchData = useCallback(async () => {
setLoading(true); // 请求开始,设置加载状态
setError(null); // 清空之前的错误
try {
const response = await fetch(url, options); // 发起 fetch 请求
if (!response.ok) { // 检查响应状态
throw new Error(`HTTP Error! Status: ${response.status}`);
}
const result = await response.json(); // 假设返回的是 JSON 格式数据
setData(result); // 将结果存储到 data 中
} catch (error) {
setError(error.message); // 捕获错误并存储
} finally {
setLoading(false); // 请求完成,更新加载状态
}
}, [url, options]);
// 使用 useEffect 来控制发起请求
useEffect(() => {
if (shouldFetch) {
fetchData(); // 如果 shouldFetch 为 true,发起请求
setShouldFetch(false); // 请求完成后,重置 shouldFetch
}
}, [url, options, shouldFetch, fetchData]);
// refetch 方法,用于手动重新发起请求
const refetch = () => {
setShouldFetch(true); // 设置 shouldFetch 为 true,触发请求
};
return { data, loading, error, refetch }; // 返回请求状态和 refetch 方法
}
export default useFetch;
class
1.实现一个符合LRU(最近最少使用) 缓存的类
class LRUCache {
constructor(capacity) {
this.capacity = capacity; // 缓存的容量
this.cache = new Map(); // 使用 Map 存储缓存项,保证 O(1) 的查找、删除、插入
}
// 获取缓存项
get(key) {
if (this.cache.has(key)) {
// 如果缓存中存在该 key,将其移到最近使用的位置
const value = this.cache.get(key);
this.cache.delete(key); // 先删除,再重新插入(确保更新顺序)
this.cache.set(key, value); // 重新插入到 Map 的末尾
return value;
}
return -1; // 如果 key 不存在,返回 -1
}
// 插入或更新缓存项
put(key, value) {
if (this.cache.has(key)) {
// 如果缓存中存在该 key,先删除旧的值
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
// 如果缓存已满,删除最久未使用的元素
// Map 中的第一个元素是最久未使用的元素
this.cache.delete(this.cache.keys().next().value);
}
// 插入新的键值对
this.cache.set(key, value);
}
}
// 测试用例
const lruCache = new LRUCache(3); // 初始化缓存,容量为 3
lruCache.put(1, 1); // 缓存是 {1=1}
lruCache.put(2, 2); // 缓存是 {1=1, 2=2}
lruCache.put(3, 3); // 缓存是 {1=1, 2=2, 3=3}
console.log(lruCache.get(1)); // 返回 1,缓存是 {1=1, 2=2, 3=3}
lruCache.put(4, 4); // 该操作会导致 2 被移除,缓存是 {1=1, 3=3, 4=4}
console.log(lruCache.get(2)); // 返回 -1 (未找到)
console.log(lruCache.get(3)); // 返回 3
console.log(lruCache.get(4)); // 返回 4
2、写个工具函数对promise封装,输入一个promise a 返回一个promise b 如果1秒内a 没有结果 则在1秒时抛出错误,否则b和a等价
function withTimeout(promise, timeout = 1000) {
return new Promise((resolve, reject) => {
// 创建一个定时器来在超时时间后抛出错误
const timer = setTimeout(() => {
reject(new Error('Operation timed out'));
}, timeout);
// 处理传入的 promise
promise
.then((result) => {
clearTimeout(timer); // 在 Promise 解析后清除定时器
resolve(result);
})
.catch((error) => {
clearTimeout(timer); // 如果 Promise 被拒绝,清除定时器
reject(error);
});
});
}
// 使用示例
const promiseA = new Promise((resolve) => {
setTimeout(() => {
resolve('Result from promiseA');
}, 500); // 500ms 后 resolve
});
withTimeout(promiseA, 1000)
.then((result) => {
console.log(result); // 如果在 1 秒内 resolve, 输出结果
})
.catch((error) => {
console.error(error); // 超时或 promiseA 拒绝时输出错误
});
3、实现一个带有并发限制的异步调度器 Scheduler,包含入队 出队 运行和暂停功能
class Scheduler {
constructor(maxConcurrency) {
this.maxConcurrency = maxConcurrency; // 最大并发数
this.queue = []; // 任务队列
this.runningTasks = 0; // 当前运行中的任务数
this.paused = false; // 调度器是否处于暂停状态
}
// 入队任务
enqueue(task) {
return new Promise((resolve, reject) => {
const wrapperTask = async () => {
if (this.paused) {
// 如果暂停,则等待继续
await new Promise((res) => {
this.resumeCallback = res;
});
}
try {
this.runningTasks++; // 增加运行中的任务数
const result = await task(); // 执行任务
resolve(result); // 任务完成后,标记成功
} catch (error) {
reject(error); // 如果任务出错,标记失败
} finally {
this.runningTasks--; // 减少运行中的任务数
this.run(); // 检查是否需要运行下一个任务
}
};
this.queue.push(wrapperTask); // 将任务加入队列
this.run(); // 立即尝试运行任务
});
}
// 出队任务(手动移除)
dequeue(task) {
const index = this.queue.indexOf(task);
if (index > -1) {
this.queue.splice(index, 1); // 从队列中移除任务
}
}
// 运行任务
run() {
if (this.paused) return; // 如果暂停,不运行任务
while (this.runningTasks < this.maxConcurrency && this.queue.length > 0) {
const task = this.queue.shift(); // 从队列中取出一个任务
task(); // 执行任务
}
}
// 暂停
pause() {
this.paused = true;
}
// 继续运行
resume() {
this.paused = false;
if (this.resumeCallback) {
this.resumeCallback(); // 唤醒暂停的任务
this.resumeCallback = null;
}
this.run(); // 继续运行任务
}
}
const scheduler = new Scheduler(2); // 最大并发数为 2
const timeout = (time) =>
new Promise((resolve) => setTimeout(resolve, time));
// 模拟任务函数
const createTask = (id, delay) => async () => {
console.log(`Task ${id} started`);
await timeout(delay);
console.log(`Task ${id} completed`);
};
// 入队任务
scheduler.enqueue(createTask(1, 3000));
scheduler.enqueue(createTask(2, 2000));
scheduler.enqueue(createTask(3, 1000));
scheduler.enqueue(createTask(4, 1500));
// 暂停和继续
setTimeout(() => {
console.log("Pausing scheduler...");
scheduler.pause();
}, 1000);
setTimeout(() => {
console.log("Resuming scheduler...");
scheduler.resume();
}, 5000);
4、链式调用实现:3秒后打印red,接着打印参数b的值,接着打印yellow
class Task {
constructor() {
this.taskQueue = []; // 任务队列
}
// 添加任务的方法,支持传递参数
add(task, ...args) {
this.taskQueue.push(() => new Promise(resolve => task(resolve, ...args)));
return this; // 链式调用
}
// 运行任务队列的方法
run() {
// 使用 reduce 链式执行任务
this.taskQueue.reduce((prevTask, currTask) => {
return prevTask.then(() => currTask());
}, Promise.resolve());
}
}
// 定义 task1、task2、task3
function task1(next) {
setTimeout(() => {
console.log('red');
next(); // 调用 next 以触发下一个任务
}, 3000);
}
function task2(next, b) {
setTimeout(() => {
console.log(b); // 打印参数 b
next(); // 调用 next 以触发下一个任务
}, 3000);
}
function task3(next) {
setTimeout(() => {
console.log('yellow');
next(); // 调用 next 以触发下一个任务
}, 2000);
}
// 使用 Task 类来添加和执行任务
const task = new Task();
task.add(task1).add(task2, 1).add(task3).run();
实现Monkey,返回的对象提供eat和sleep两个函数,支持链式调用。具体调用方式如下所示:Monkey('Alan').eat('Banana').sleep(4).eat('Apple').sleep(5).eat('Pear')
class Monkey {
constructor(name) {
this.name = name;
this.queue = []; // 异步任务队列
console.log(`my name is ${name}`);
// 开始执行任务队列
setTimeout(() => {
this.runQueue();
}, 0);
}
eat(food) {
// 将 eat 任务推入队列
this.queue.push(() => {
console.log(`I eat ${food}`);
return Promise.resolve();
});
return this; // 返回当前实例以支持链式调用
}
sleep(seconds) {
// 将 sleep 任务推入队列
this.queue.push(() => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`// 等待 ${seconds} s`);
resolve();
}, seconds * 1000);
});
});
return this; // 返回当前实例以支持链式调用
}
async runQueue() {
// 按顺序执行队列中的任务
for (const task of this.queue) {
await task();
}
}
}
// 测试代码
new Monkey('Alan').eat('Banana').sleep(4).eat('Apple').sleep(5).eat('Pear');
5.发布订阅类EventEmitter
class EventEmitter {
constructor() {
this.list = {}
}
// 订阅事件(subscribe)
on(event, callback) {
if (!this.list[event]) {
this.list[event] = []
}
this.list[event].push(callback)
}
// 发布事件(publish)
emit(event, ...args) {
if (this.list[event]) {
this.list[event].forEach(fn => {
fn.apply(this, args)
});
}
}
// 取消订阅(unsubscribe)
off(event, callback) {
if (this.list[event] && callback) {
this.list[event] = this.list[event].filter(fn => fn !== callback)
}
}
// once方法用于仅订阅一次事件,即回调函数只会被执行一次
once(event, callback) {
const onceCallback = (...args) => {
callback.apply(this, args)
this.off(event, onceCallback)
}
this.on(event, onceCallback)
}
}
function hello(...data) {
console.log('hello' + data);
}
const emitter = new EventEmitter()
// 使用 once 方法订阅事件,回调函数只会被执行一次
emitter.once('onSell', hello)
// 触发事件,只会执行一次回调函数
emitter.emit('onSell', '1', '2', '3')
emitter.emit('onSell', '1', '2', '3')
6.有一种花, 两种鸟, 花定时开放,鸟看到花开会叫, 鸟的叫声不一样
class EventBus {
constructor(){
this.list = {}
}
on(fnName,fn){
if(!this.list[fnName]) this.list[fnName] = []
this.list[fnName].push(fn)
}
emit(fnName,...args){
if(this.list[fnName]){
this.list[fnName].forEach(fn => {
fn.apply(this,args)
});
}
}
}
const events = new EventBus()
// 发布者
class Flower{
constructor(){}
open(delay){
setTimeout(()=>{
events.emit('flowerOpen')
}, delay)
}
}
// 订阅者
class Bird{
constructor(name,sound){
this.name = name
this.sound = sound
events.on('flowerOpen', this.makeSound.bind(this))
}
makeSound(){
console.log(this.name, this.sound)
}
}
// 测试
const myFlower = new Flower()
const bird1 = new Bird('A', '布谷布谷')
const bird2 = new Bird('B', '叽叽喳喳')
myFlower.open(1000)
JS
1.用链表实现一个队列js实现
class Node {
constructor(value) {
this.value = value; // 节点的值
this.next = null; // 指向下一个节点的指针
}
}
class Queue {
constructor() {
this.front = null; // 队列的头部(出队的一端)
this.rear = null; // 队列的尾部(入队的一端)
this.length = 0; // 队列中的元素数量
}
// 入队操作:在队列末尾添加元素
enqueue(value) {
const newNode = new Node(value); // 创建一个新的节点
if (this.rear) {
this.rear.next = newNode; // 将新节点添加到尾部
}
this.rear = newNode; // 更新尾部为新节点
if (!this.front) {
this.front = newNode; // 如果队列为空,头部也指向新节点
}
this.length++; // 增加队列的长度
}
// 出队操作:移除并返回队列头部的元素
dequeue() {
if (!this.front) {
return null; // 如果队列为空,返回 null
}
const removedNode = this.front; // 保存当前头部节点
this.front = this.front.next; // 将头部更新为下一个节点
if (!this.front) {
this.rear = null; // 如果移除后队列为空,尾部也要置为 null
}
this.length--; // 减少队列长度
return removedNode.value; // 返回移除的节点的值
}
// 查看队列头部元素
peek() {
return this.front ? this.front.value : null; // 如果队列为空,返回 null
}
// 判断队列是否为空
isEmpty() {
return this.length === 0;
}
// 获取队列长度
size() {
return this.length;
}
}
const queue = new Queue();
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
console.log(queue.peek()); // 输出 10
console.log(queue.dequeue()); // 输出 10
console.log(queue.size()); // 输出 2
console.log(queue.isEmpty()); // 输出 false
2. 在字符串中找出最大数字及其变式
// 1.基本实现
function findLargestNumber(str) {
// 使用正则表达式匹配字符串中的所有数字
const numbers = str.match(/\d+/g);
// 如果没有匹配到数字,返回 null
if (!numbers) return null;
// 使用 Math.max 找出最大值
const maxNumber = Math.max(...numbers.map(Number));
return maxNumber;
}
// 2 不用正则,考虑字符串里无数字情况
function findLargestNumber(str) {
let maxNumber = -Infinity; // 初始化为负无穷大,方便处理没有数字的情况
let currentNumber = 0;
let inNumber = false; // 标记是否在处理数字
let hasNumber = false; // 标记是否有遇到数字
for (let i = 0; i < str.length; i++) {
const char = str[i];
// 如果字符是数字
if (char >= '0' && char <= '9') {
currentNumber = currentNumber * 10 + (char - '0'); // 构建当前数字
inNumber = true;
hasNumber = true; // 标记已经遇到了数字
} else {
// 遇到非数字字符时,检查当前数字并更新最大值
if (inNumber) {
maxNumber = Math.max(maxNumber, currentNumber);
currentNumber = 0; // 重置当前数字
inNumber = false;
}
}
}
// 处理最后一个数字
if (inNumber) {
maxNumber = Math.max(maxNumber, currentNumber);
}
// 如果没有找到任何数字,返回 null
return hasNumber ? maxNumber : null;
}
// 3.允许str中有负数
function findLargestNumber(str) {
let maxNumber = -Infinity; // 初始化为负无穷大
let currentNumber = 0;
let sign = 1; // 用于标记当前数字的正负
let inNumber = false; // 标记是否在处理数字
let hasNumber = false; // 标记是否遇到了数字
for (let i = 0; i < str.length; i++) {
const char = str[i];
// 检查负号,负号后面必须跟数字
if (char === '-' && i + 1 < str.length && str[i + 1] >= '0' && str[i + 1] <= '9') {
sign = -1;
}
// 如果是数字,构建当前数字
else if (char >= '0' && char <= '9') {
currentNumber = currentNumber * 10 + (char - '0');
inNumber = true;
hasNumber = true;
}
// 非数字或负号,处理当前数字
else if (inNumber) {
maxNumber = Math.max(maxNumber, currentNumber * sign);
currentNumber = 0;
inNumber = false;
sign = 1; // 重置正负标记
}
}
// 处理最后一个数字
if (inNumber) {
maxNumber = Math.max(maxNumber, currentNumber * sign);
}
// 如果没有数字,返回 null
return hasNumber ? maxNumber : null;
}
3.单链表判断是否有环及其变式
// 1.快慢指针实现
function hasCycle(head) {
let slow = head;
let fast = head;
while (fast !== null && fast.next !== null) {
slow = slow.next; // 慢指针每次走一步
fast = fast.next.next; // 快指针每次走两步
if (slow === fast) { // 快慢指针相遇,说明有环
return true;
}
}
return false; // 快指针遇到null,说明没有环
}
// 2.怎么确定环的长度
function cycleLength(head) {
let slow = head;
let fast = head;
// 先找到快慢指针相遇的地方
while (fast !== null && fast.next !== null) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
// 计算环的长度
let length = 0;
do {
fast = fast.next;
length++;
} while (slow !== fast);
return length;
}
}
return 0; // 没有环
}
// 3.怎么确定入环点
// 相遇时,快指针已经走了比慢指针多 n 圈,即从起点走到环的入口与从相遇点走到环的入口需要的步数相同。因此将慢指针重置到链表头部,与快指针一起一步步移动,最终会在环的入口节点相遇。
function findCycleStart(head) {
let slow = head;
let fast = head;
// 首先通过快慢指针找到相遇点
while (fast !== null && fast.next !== null) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
// 找到相遇点后,将慢指针移回到起点
slow = head;
// 两个指针每次走一步,相遇点即为入环点
while (slow !== fast) {
slow = slow.next;
fast = fast.next;
}
return slow; // 入环点
}
}
return null; // 没有环
}
4.实现函数柯里化
const curry = (fn) => {
return function curried(...args){
if(args.length>=fn.length){
return fn(...args)
} else {
return function(...args2){
return curried(...args, ...args2)
}
}
}
}
5.给一个嵌套对象查找其属性路径对应的值用数组形式返回
function findNestedProperties(obj) {
const result = [];
function recurse(currentObj, currentPath) {
for (const key in currentObj) {
if (currentObj.hasOwnProperty(key)) {
const newPath = currentPath ? `${currentPath}${key}` : key;
// 检查是否为基本数据类型或数组
if (typeof currentObj[key] !== 'object' || currentObj[key] === null || Array.isArray(currentObj[key])) {
result.push({ key: newPath, value: currentObj[key] });
} else {
// 如果是对象,则递归
recurse(currentObj[key], newPath);
}
}
}
}
recurse(obj, '');
return result;
}
6.实现一个对象浅比较
function shallowEqual(obj1, obj2) {
// 如果引用相同,直接返回 true
if (obj1 === obj2) return true;
// 如果其中一个是 null 或 undefined,另一个不是,直接返回 false
if (obj1 == null || obj2 == null) return false;
// 获取对象的属性名称
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
// 如果两个对象的属性数量不同,直接返回 false
if (keys1.length !== keys2.length) return false;
// 遍历属性,比较每个属性的值
for (let key of keys1) {
// 使用严格相等比较值
if (obj1[key] !== obj2[key]) {
return false;
}
}
return true;
}
// 示例用法
const obj1 = { a: 1, b: 2 };
const obj2 = { a: 1, b: 2 };
const obj3 = { a: 1, b: 3 };
console.log(shallowEqual(obj1, obj2)); // true
console.log(shallowEqual(obj1, obj3)); // false
7.兔子吃草
// 找到有毒的草堆,需要多少只兔子
function findPoisonousGrass(numGrass, poisonedIndex) {
// 计算需要多少位二进制来表示所有草堆的编号
const binaryLength = Math.ceil(Math.log2(numGrass)); // 需要的二进制位数
// 将有毒草堆编号转换为二进制字符串,补齐到 binaryLength 位
const poisonedBinary = poisonedIndex.toString(2).padStart(binaryLength, '0');
// 计算需要死亡的兔子的数量
let deadRabbitCount = 0;
for (let i = 0; i < poisonedBinary.length; i++) {
if (poisonedBinary[i] === '1') {
deadRabbitCount++;
}
}
// 返回死亡兔子的数量
return deadRabbitCount;
}
// 假设毒草是第 678 堆草
const numGrass = 1000;
const poisonedIndex = 678; // 假设第 678 堆草是有毒的
const deadRabbitCount = findPoisonousGrass(numGrass, poisonedIndex);
console.log(`The number of rabbits that need to die: ${deadRabbitCount}`);
// 哪几只兔子会死
function findPoisonousGrass(numGrass, poisonedIndex) {
// 计算需要多少位二进制来表示所有草堆的编号
const binaryLength = Math.ceil(Math.log2(numGrass)); // 需要的二进制位数
// 将有毒草堆编号转换为二进制字符串,补齐到 binaryLength 位
const poisonedBinary = poisonedIndex.toString(2).padStart(binaryLength, '0');
// 计算哪些兔子需要死
const rabbitsToDie = [];
for (let i = 0; i < binaryLength; i++) {
if (poisonedBinary[i] === '1') {
rabbitsToDie.push(i + 1); // 兔子的编号从1开始
}
}
console.log(`The rabbits that need to die: ${rabbitsToDie.join(', ')}`);
}
// 假设毒草是第 678 堆草
const numGrass = 1000;
const poisonedIndex = 678;
findPoisonousGrass(numGrass, poisonedIndex);
8.分页效果 [1],2,3...99,100 1,2,[3]4,...99,100 1,...,4,[5],6,...99,100
const generatePageNumbers = () => {
const pages = [];
// Always show the first page
pages.push(1);
// Add "..." if there is a gap between first page and current page
if (currentPage > 3) {
pages.push('...');
}
// Show two pages before the current page, but don't go below 1
for (let i = Math.max(currentPage - 2, 2); i < currentPage; i++) {
pages.push(i);
}
// Show the current page
pages.push(currentPage);
// Show two pages after the current page, but don't go beyond totalPages
for (let i = currentPage + 1; i <= Math.min(currentPage + 2, totalPages - 1); i++) {
pages.push(i);
}
// Add "..." if there is a gap between last page and current page
if (currentPage < totalPages - 2) {
pages.push('...');
}
// Always show the last page
if (totalPages > 1) {
pages.push(totalPages);
}
return pages;
};
9.求子数组的最大和、最大积
// 子数组最大和
function maxSubArray(nums) {
let maxSum = nums[0]; // 初始化最大子数组和
let currentSum = nums[0]; // 当前子数组和
let start = 0, end = 0; // 最大子数组的起始和结束索引
let tempStart = 0; // 临时记录当前子数组的起始索引
for (let i = 1; i < nums.length; i++) {
// 如果当前元素和当前和之和大于当前元素,则继续累加,否则重新开始新子数组
if (currentSum + nums[i] > nums[i]) {
currentSum += nums[i];
} else {
currentSum = nums[i];
tempStart = i; // 重新开始一个新子数组
}
// 更新最大和和子数组的起始和结束位置
if (currentSum > maxSum) {
maxSum = currentSum;
start = tempStart;
end = i;
}
}
// 提取最大子数组
const subarray = nums.slice(start, end + 1);
return { maxSum, subarray };
}
// 示例
const nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4];
const result = maxSubArray(nums);
console.log("最大子数组和:", result.maxSum);
console.log("最大子数组:", result.subarray);
// 子数组最大积1
function maxProductSubArray(nums) {
let maxProduct = nums[0]; // 当前子数组的最大积
let minProduct = nums[0]; // 当前子数组的最小积
let result = nums[0]; // 记录结果,最终返回的最大积
for (let i = 1; i < nums.length; i++) {
// 如果当前数是负数,交换最大积和最小积
if (nums[i] < 0) {
[maxProduct, minProduct] = [minProduct, maxProduct];
}
// 更新最大积和最小积
maxProduct = Math.max(nums[i], maxProduct * nums[i]);
minProduct = Math.min(nums[i], minProduct * nums[i]);
// 更新结果
result = Math.max(result, maxProduct);
}
return result;
}
// 示例
const nums = [2, 3, -2, 4];
const result = maxProductSubArray(nums);
console.log("最大子数组积:", result);
// 动态规划法求积
class Solution {
maxProduct(nums) {
if (nums.length === 0) return 0;
let maxStack = [nums[0]];
let minStack = [nums[0]];
for (let i = 1; i < nums.length; i++) {
const n1 = maxStack[maxStack.length - 1] * nums[i];
const n2 = minStack[minStack.length - 1] * nums[i];
const n3 = nums[i];
maxStack.push(Math.max(n1, n2, n3));
minStack.push(Math.min(n1, n2, n3));
}
return Math.max(...maxStack);
}
}
// 示例
const solution = new Solution();
const nums = [2, 3, -2, 4];
const result = solution.maxProduct(nums);
console.log(result); // 输出 6
10.模板引擎(模板中有空格)
function templateEngine(template, data) {
return template.replace(/{{\s*(\w+)\s*}}/g, (_, key) => {
// 从数据中获取对应值
const value = data[key.trim()];
// 如果存在值,替换占位符;否则返回占位符本身
return value !== undefined ? value : `{{${key}}}`;
});
}
// 示例用法
const template = `
Hello, {{ name }}!
Today is {{ day }}.
Weather: {{weather}}
`;
const data = {
name: "Alice",
day: "Monday",
weather: "Sunny"
};
console.log(templateEngine(template, data));
给定一组存在 ${a.b.c}形式占位符的字符串和一组数据,将字符串中的占位替换成真实的数据并输出
const data = {
date: '2022年9月',
model: 'iPhone 14',
price: { startPrice: 5999 }
};
const tpl = '苹果公司在 ${date} 发布了全新的 ${model} 系列手机,起售价格 ${price.startPrice} 元';
// 模板解析函数
const getTpl = (data, tpl) => {
return tpl.replace(/\$\{([\w.]+)\}/g, (_, path) => {
// 使用递归解析路径
return path.split('.').reduce((res, key) => res[key], data) || '';
});
};
// 调用并打印结果
const result = getTpl(data, tpl);
console.log(result);
- 实现两数近似和
/**
* 找到数组中所有两个数的和最接近目标值的数对,并返回它们的下标
* @param {number[]} nums - 整数数组
* @param {number} target - 目标值
* @return {number[][]} - 所有最接近目标值的数对的下标
*/
function twoSumClosest(nums, target) {
if (nums.length < 2) {
throw new Error("数组中至少需要两个元素");
}
// 创建一个包含元素值和原始下标的数组
const numsWithIndices = nums.map((num, index) => ({ num, index }));
// 对新的数组按照元素值进行排序
numsWithIndices.sort((a, b) => a.num - b.num);
let left = 0;
let right = numsWithIndices.length - 1;
let closestSum = numsWithIndices[left].num + numsWithIndices[right].num;
let minDiff = Math.abs(closestSum - target);
let result = [[numsWithIndices[left].index, numsWithIndices[right].index]];
while (left < right) {
const currentSum = numsWithIndices[left].num + numsWithIndices[right].num;
const currentDiff = Math.abs(currentSum - target);
if (currentDiff < minDiff) {
// 找到新的更接近的和,清空之前的结果并添加当前对
closestSum = currentSum;
minDiff = currentDiff;
result = [[numsWithIndices[left].index, numsWithIndices[right].index]];
} else if (currentDiff === minDiff) {
// 找到相同最小差值的和,添加到结果中
const newPair = [numsWithIndices[left].index, numsWithIndices[right].index];
// 确保小的下标在前,避免 [1,0] 和 [0,1] 这样的重复
newPair.sort((a, b) => a - b);
// 检查是否已经存在该对
const lastPair = result[result.length - 1];
if (!(lastPair[0] === newPair[0] && lastPair[1] === newPair[1])) {
result.push(newPair);
}
}
// 根据当前和与目标值的比较,移动指针
if (currentSum < target) {
left++;
} else if (currentSum > target) {
right--;
} else {
// 当 currentSum === target 时,同时移动两个指针以查找其他可能的数对
left++;
right--;
}
}
return result;
}
// 示例用法
const nums1 = [-1, 2, 1, -4];
const target1 = 1;
const result1 = twoSumClosest(nums1, target1);
console.log(`最接近目标 ${target1} 的数对的下标是:`, result1);
// 输出: 最接近目标 1 的数对的下标是: [ [ 0, 1 ] ]
const nums2 = [-1, 2, 1, -4, 3, 0];
const target2 = 1;
const result2 = twoSumClosest(nums2, target2);
console.log(`最接近目标 ${target2} 的数对的下标是:`, result2);
// 输出: 最接近目标 1 的数对的下标是: [ [ 0, 1 ], [ 2, 5 ] ]
const nums3 = [1, 2, 3, 2, 1];
const target3 = 4;
const result3 = twoSumClosest(nums3, target3);
console.log(`最接近目标 ${target3} 的数对的下标是:`, result3);
// 输出: 最接近目标 4 的数对的下标是: [ [ 1, 2 ], [ 1, 3 ], [ 2, 4 ] ]
console.log(twoSumClosest([2, 7, 11, 15], 10)); // 输出: [0, 1] (2+7最接近10)
console.log(twoSumClosest([1, 3, 5, 8], 7)); // 输出: [1, 2] (3+5最接近7)
console.log(twoSumClosest([3, 8, 12, 17], 20)); // 输出: [1, 2] (8+12最接近20)
console.log(twoSumClosest([1, 1, 1, 1], 10)); // 输出: [0, 1] (1+1最接近10)
console.log(twoSumClosest([-1, 2, 1, -4], 1)); // 输出: [1, 2] (2+1最接近1)
12.时间戳输出对应文案:如 [一分钟内]刚刚、x分钟前、x小时前、昨天 xx:xx ,前天,【一星期内】星期几,【超过一星期】xx月xx日xx时xx分,【不在当年】xx年xx月xx日xx时xx分
function timeAgoIntl(timestamp){
let inputTime
if(typeof timestamp === 'number'){
if (timestamp.toString().length === 10){
inputTime = new Date(timestamp*1000)
} else {
inputTime = new Date(timestamp)
}
} else if(typeof timestamp === 'string'){
inputTime = new Date(timestamp)
} else if(timestamp instanceof Date){
inputTime = timestamp
} else {
throw new Error('invalid timestamp')
}
const now = new Date()
const diffInSeconds = (now - inputTime) / 1000
const rtf = new Intl.RelativeTimeFormat('zh-CN',{numeric: 'auto'})
const thresholds = [
{limit:60, divisor:1, unit:'second'},
{limit:3600, divisor:60, unit:'minute'},
{limit:86400, divisor:3600, unit:'hour'},
{limit:604800, divisor:86400, unit:'day'},// todo
]
for(let i=0; i<thresholds.length; i++){
if(diffInSeconds<thresholds[i].limit){
const value = Math.floor(diffInSeconds/thresholds[i].divisor)
return rtf.format(-value,thresholds[i].unit)
}
}
}
const timestampsIntl = [
Date.now()-30*1000, // 刚刚
Date.now()-5*60*1000, // 5分钟前
Date.now()-5*3600*1000, // 5小时前
Date.now()-5*86400*1000, // 5天前
]
timestampsIntl.forEach(ts => {
console.log(timeAgoIntl(ts))
})
13.实现方法f,判断以下图结构中,是否存在闭环?并打印出闭环上的节点
function detectCycle(graph) {
// 构建邻接表表示图
const adjacencyList = {};
for (const edge of graph) {
const { src, dst } = edge;
if (!adjacencyList[src]) adjacencyList[src] = [];
adjacencyList[src].push(dst);
}
const visited = new Set(); // 已访问节点
const stack = new Set(); // 当前路径上的节点(用于检测环)
const cycleNodes = new Set(); // 存储闭环上的节点
// 深度优先搜索函数
function dfs(node) {
if (stack.has(node)) {
// 找到了环,将环上的节点加入到 cycleNodes
cycleNodes.add(node);
return node; // 返回环的起始节点
}
if (visited.has(node)) return null;
visited.add(node);
stack.add(node);
if (adjacencyList[node]) {
for (const neighbor of adjacencyList[node]) {
const cycleStart = dfs(neighbor);
if (cycleStart) {
cycleNodes.add(node); // 当前节点属于环
if (cycleStart === node) return null; // 环已经完整
return cycleStart; // 继续向上返回环的起始节点
}
}
}
stack.delete(node); // 回溯时移除当前节点
return null;
}
// 遍历所有节点,尝试检测环
for (const node in adjacencyList) {
if (!visited.has(node)) {
dfs(node);
if (cycleNodes.size > 0) {
console.log("闭环上的节点:", Array.from(cycleNodes));
return true;
}
}
}
console.log("图中不存在闭环");
return false;
}
// 测试
var graph = [
{ src: 'g', dst: 'e' },
{ src: 'a', dst: 'b' },
{ src: 'f', dst: 'g' },
{ src: 'e', dst: 'f' },
{ src: 'c', dst: 'd' },
{ src: 'b', dst: 'c' },
];
detectCycle(graph); // ['g', 'f', 'e']
14.企鹅们都需要穿文化衫来拍照。一次采访中,记者随机遇到的企鹅,企鹅会告诉记者还有多少企鹅跟他穿一个颜色的文化衫(每个企鹅说的都是真实情况)。我们将这些回答放在 answers 数组里。返回鹅厂中企鹅的最少数量。
function minimumPenguins(answers) {
const map = new Map();
// 统计每个回答出现的次数
for (let num of answers) {
map.set(num, (map.get(num) || 0) + 1);
}
let minCount = 0;
// 遍历 map 计算最少数量
for (let [num, count] of map) {
// 每组有 num + 1 只企鹅
const groupSize = num + 1;
// 至少需要 Math.ceil(count / groupSize) 个组
const groups = Math.ceil(count / groupSize);
// 累加企鹅的总数
minCount += groups * groupSize;
}
return minCount;
}
// 示例测试
console.log(minimumPenguins([1, 1, 2])); // 输出: 5
console.log(minimumPenguins([1])); // 输出: 2
function minimumPenguins(answers) {
const countArray = []; // 用数组记录每个回答的次数
// 统计每个回答出现的次数
for (let num of answers) {
countArray[num] = (countArray[num] || 0) + 1;
}
let minCount = 0;
// 遍历 countArray 计算最少数量
for (let num = 0; num < countArray.length; num++) {
if (countArray[num] > 0) {
const groupSize = num + 1; // 每组有 num + 1 只企鹅
const groups = Math.ceil(countArray[num] / groupSize); // 至少需要的组数
minCount += groups * groupSize; // 累加最少企鹅总数
}
}
return minCount;
}
// 示例测试
console.log(minimumPenguins([1, 1, 2])); // 输出: 5
console.log(minimumPenguins([1])); // 输出: 2
15.买股票的最佳时机含手续费 lc714
var maxProfit = function(prices, fee) {
const n = prices.length;
const dp = new Array(n).fill(0).map(v => new Array(2).fill(0));
dp[0][0] = 0, dp[0][1] = -prices[0];
for (let i = 1; i < n; ++i) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[n - 1][0];
};
16.对象扁平化
// 扁平化 Object {a:1,b:{a:{c:1,d:2}}} => {a:1,c:1,d:2}
function flatObj(obj){
// 补充完成
const res = {}
if(typeof obj !== 'object' || obj === null){
return obj
}
for(const key in obj){
const value = obj[key]
if(typeof value === 'object' && !Array.isArray(value)){
const child = flatObj(value)
for(const leaf in child){
res[leaf] = child[leaf]
}
}
else {
res[key] = obj[key]
}
}
return res
}
const obj = {a:1,b:{a:{c:1,d:2}}}
console.log(flatObj(obj))
17.队列中可以看到的人 lc1944
var canSeePersonsCount = function(heights) {
const n = heights.length;
const stack = [];
const res = new Array(n).fill(0);
for (let i = n - 1; i >= 0; i--) {
const h = heights[i];
while (stack.length > 0 && stack[stack.length - 1] <= h) {
stack.pop();
res[i] += 1;
}
if (stack.length > 0) {
res[i] += 1;
}
stack.push(h);
}
return res;
};
// 示例
const heights = [10, 6, 8, 5, 11, 9];
console.log(canSeePersonsCount1(heights)); // 输出: [3, 1, 2, 1, 1, 0]
18.找到嵌套属性值与对应路径
// 输入:
var a = {
a: {
b: {
c: 1
},
d: [1,2]
},
e: 's'
}
// 输出:[{key: 'abc', value: 1}, {key: 'ad', value: [1,2]}, {key: 'e', value: 's'}]
function findNestedProperties(obj) {
const result = [];
function recurse(currentObj, currentPath) {
for (const key in currentObj) {
if (currentObj.hasOwnProperty(key)) {
const newPath = currentPath ? `${currentPath}${key}` : key;
// 检查是否为基本数据类型或数组
if (typeof currentObj[key] !== 'object' || currentObj[key] === null || Array.isArray(currentObj[key])) {
result.push({ key: newPath, value: currentObj[key] });
} else {
// 如果是对象,则递归
recurse(currentObj[key], newPath);
}
}
}
}
recurse(obj, '');
return result;
}
19.实现深拷贝
function deepClone(obj, hash = new WeakMap()) {
// 处理基本数据类型
if (obj === null || typeof obj !== "object") return obj;
// 避免循环引用
if (hash.has(obj)) return hash.get(obj);
// 处理特殊类型
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 创建新的对象或数组
const copy = Array.isArray(obj) ? [] : {};
hash.set(obj, copy);
// 遍历对象属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepClone(obj[key], hash); // 递归拷贝
}
}
return copy;
}
// 测试
const obj = {
a: 1,
b: [1, 2],
c: { d: 3 },
date: new Date(),
reg: /test/gi,
};
obj.self = obj; // 循环引用
const cloned = deepClone(obj);
console.log(cloned);
console.log(cloned.date instanceof Date); // true
console.log(cloned.reg instanceof RegExp); // true
other
// app.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
const User = require('./models/User'); // 引入数据库
// 连接 MongoDB 数据库
mongoose.connect('mongodb://localhost:27017/myapp', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Connected to MongoDB'))
.catch(err => console.log('MongoDB connection error:', err));
// 设置视图引擎为 EJS
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// 中间件设置
app.use(bodyParser.urlencoded({ extended: true })); // 解析 URL 编码的请求体
app.use(bodyParser.json()); // 解析 JSON 请求体
// 静态文件托管
app.use(express.static(path.join(__dirname, 'public')));
// 首页路由
app.get('/', (req, res) => {
res.render('index', { title: 'My Node Web App' });
});
// 简单的 POST 路由
app.post('/submit', (req, res) => {
const { name, email } = req.body;
const newUser = new User({ name, email });
await newUser.save();
res.send(`Data has been saved to the database: Name = ${name}, Email = ${email}`);
});
// 404 路由
app.use((req, res) => {
res.status(404).send('Page not found');
});
// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
// models/User.js 提交表单时将数据存储到数据库
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: String,
email: String
});
const User = mongoose.model('User', userSchema);
module.exports = User;
// <!-- views/index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<h1>Welcome to <%= title %></h1>
<form action="/submit" method="POST">
<label for="name">Name:</label>
<input type="text" name="name" id="name" required><br><br>
<label for="email">Email:</label>
<input type="email" name="email" id="email" required><br><br>
<button type="submit">Submit</button>
</form>
</body>
</html>
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
# 创建一个 OpenAI 模型实例
llm = ChatOpenAI(model="gpt-4", temperature=0)
# 创建一个提示模板,用于代码优化
prompt = PromptTemplate(
input_variables=["code"],
template="你是一个前端开发专家,下面的 JavaScript 代码存在性能或可读性问题,请优化这段代码并给出优化后的版本。代码如下:\n{code}\n\n优化后的代码:"
)
# 使用 LLMChain 创建链
chain = LLMChain(llm=llm, prompt=prompt)
# 示例代码
code_to_optimize = """
function sumArray(arr) {
let total = 0;
for (let i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
"""
# 调用 LangChain 链生成优化后的代码
optimized_code = chain.run({"code": code_to_optimize})
print(optimized_code)