一些场景题

目录

c2.一个div嵌套三个div 外层div为flex布局 实现内层俩个div靠左 第三个div靠右,怎么写样式

1.实现一个符合 LRU (最近最少使用) 缓存的类

2.写个工具函数对promise封装,输入一个promise a 返回一个promise b 如果1秒内a 没有结果 则在1秒时抛出错误,否则b和a等价

3.编写一个倒计时ui组件 组件有俩个参数:截止时间deadline和时间到期时执行的回调函数cb

4.实现一个带有并发限制的异步调度器 Scheduler

5.要求3秒后打印red,接着打印参数b的值,接着打印yellow

6.用链表实现一个队列js实现

7.在字符串中找出最大数字及其变式

8.单链表判断是否有环及其变式

9.实现函数柯里化 

10.给一个嵌套对象查找其属性路径对应的值用数组形式返回

11.实现一个对象浅比较

12. 兔子吃草

13. 实现一个分页

14.求子数组的最大和、最大积

15.实现useFetch

16.用node.j s 写完整的web应用

17.Langchain模型优化代码

18.发布订阅类EventEmitter 

19. 画一个表盘,实现分针和秒钟的旋转动画

20.模板引擎(模板中有空格)

21.实现2数近似和

22. 给时间戳输出对应文案:如 [一分钟内]刚刚、x分钟前、x小时前、昨天 xx:xx ,前天,【一星期内】星期几,【超过一星期】xx月xx日xx时xx分,【不在当年】xx年xx月xx日xx时xx分

23.有一种花, 两种鸟, 花定时开放,鸟看到花开会叫, 鸟的叫声不一样,用代码来实现这样一种场景


 c1.两个嵌套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% 会使得高度和宽度相等,从而实现正方形效果。
*/
c2.一个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 推到最右边 */
}

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.编写一个倒计时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;
4.实现一个带有并发限制的异步调度器 Scheduler
class Scheduler {
  constructor() {
    this.tasks = []; // 存储任务
    this.runningCount = 0; // 当前正在运行的任务数
    this.maxConcurrency = 2; // 最大并发度
  }

  // 添加任务
  add(task) {
    return new Promise((resolve) => {
      const wrappedTask = async () => {
        await task(); // 执行任务
        resolve(); // 任务完成后解析 Promise
      };
      this.tasks.push(wrappedTask);
    });
  }

  // 运行任务
  async run() {
    const runTask = async (task) => {
      this.runningCount++; // 增加正在运行的任务数
      await task(); // 执行任务
      this.runningCount--; // 任务完成,减少计数
      this.executeNext(); // 继续执行下一个任务
    };

    this.executeNext = () => {
      if (this.tasks.length === 0 || this.runningCount >= this.maxConcurrency) return; // 任务队列为空或达到并发限制

      const task = this.tasks.shift(); // 取出下一个任务
      runTask(task); // 运行任务
    };

    // 启动最大并发数的任务
    for (let i = 0; i < this.maxConcurrency; i++) {
      this.executeNext();
    }
  }

  // 创建任务
  addTask(runTime, taskId) {
    const task = () => new Promise(resolve => {
    //   console.log(`Task ${taskId} started, will take ${runTime} ms`);
      setTimeout(() => {
        // console.log(`Task ${taskId} completed`);
        console.log(taskId);
        resolve();
      }, runTime);
    });
    return this.add(task); // 添加任务并返回 Promise
  }
}

// 使用示例
const scheduler = new Scheduler();

// 添加任务
scheduler.addTask(2000, 1); // Task 1: 2000 ms
scheduler.addTask(1000, 2); // Task 2: 1000 ms
scheduler.addTask(1500, 3); // Task 3: 1500 ms
scheduler.addTask(500, 4); // Task 4: 500 ms

// 运行调度器
scheduler.run();
class Scheduler {
    constructor() {
       // to do
       this.tasks = []
       this.runningCount = 0
       this.maxCount = 2
    }
    add(task) {
      //to do
      return new Promise((resolve)=>{
        const wrappedTask = async ()=>{
            await task()
            resolve()
        }
        this.tasks.push(wrappedTask)
      })
      
    }
    run() {
      // to do
      const runTask = async (task)=>{
        this.runningCount++
        await task()
        this.runningCount--
        this.executeNext()
      }
      this.executeNext = ()=>{
        if(this.tasks.length===0 || this.runningCount>=this.maxCount)
            return 
        else {
            const task = this.tasks.shift()
            runTask(task) 
        }
      }
      for(let i=0;i<this.maxCount;i++)
        this.executeNext()
    }
}
const timeout = (time) => new Promise(resolve => {
    setTimeout(resolve, time)
})
const scheduler = new Scheduler()
const addTask = (time, order) => {
    scheduler.add(() => timeout(time)).then(() => console.log(order))
}
addTask(400, 4)
addTask(200, 2)
addTask(400, 3)
addTask(100, 1) //2 4 1 3

scheduler.run(); // to do

// 以下是不写run方法:

class Scheduler {
    constructor(max) {
        this.max = max;
        this.count = 0; // 用来记录当前正在执行的异步函数
        this.queue = new Array(); // 表示等待队列
    }
    async add(promiseCreator) {
        /*
            此时count已经满了,不能执行;本次add需要阻塞在这里,将resolve放入队列中等待唤醒,
            等到count<max时,从队列中取出执行resolve,执行,await执行完毕,本次add继续
        */
        if (this.count >= this.max) {
            await new Promise((resolve, reject) => this.queue.push(resolve));
        }
 
        this.count++;
        let res = await promiseCreator();
        this.count--;
        if (this.queue.length) {
        // 依次唤醒add;若队列中有值,将其resolve弹出,并执行;以便阻塞的任务,可以正常执行
        this.queue.shift()();
        }
        return res;
    }
}
5.要求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();
6.用链表实现一个队列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
7.在字符串中找出最大数字及其变式

// 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;
}
8.单链表判断是否有环及其变式
// 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; // 没有环
}
9.实现函数柯里化 
const curry = (fn) => {
    return function curried(...args){
        if(args.length>=fn.length){
            return fn(...args)
        } else {
            return function(...args2){
                return curried(...args, ...args2)
            }
        }
    }
}
10.给一个嵌套对象查找其属性路径对应的值用数组形式返回
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;
}
11.实现一个对象浅比较
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
12. 兔子吃草
// 找到有毒的草堆,需要多少只兔子
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);
13. 实现一个分页

[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;
  };
14.求子数组的最大和、最大积
// 子数组最大和
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
15.实现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;
16.用node.j s 写完整的web应用
// 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>
17.Langchain模型优化代码
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)
18.发布订阅类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') 
19. 画一个表盘,实现分针和秒钟的旋转动画
<!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();

20.模板引擎(模板中有空格)
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));
21.实现2数近似和
/**
 * 找到数组中所有两个数的和最接近目标值的数对,并返回它们的下标
 * @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)
22. 给时间戳输出对应文案:如 [一分钟内]刚刚、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))
})

23.有一种花, 两种鸟, 花定时开放,鸟看到花开会叫, 鸟的叫声不一样,用代码来实现这样一种场景
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) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白目

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值