🔥大厂常考的算法题和手写题

前言

在面试里常遇到的面试题和手写题进行阶段总结。

模拟实现 Promise.all Promise.race Promise.allSettled

JavaScript 复制代码
// 模拟实现Promise.all
function customPromiseAll(promises) {
  return new Promise((resolve, reject) => {
    let results = [];
    let completedPromises = 0;

    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then((result) => {
          results[index] = result;
          completedPromises++;
          if (completedPromises === promises.length) {
            resolve(results);
          }
        })
        .catch((error) => {
          reject(error);
        });
    });
  });
}

// 模拟实现Promise.race
function customPromiseRace(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach((promise) => {
      Promise.resolve(promise)
        .then((result) => {
          resolve(result);
        })
        .catch((error) => {
          reject(error);
        });
    });
  });
}

// 模拟实现Promise.allSettled
function customPromiseAllSettled(promises) {
  return new Promise((resolve) => {
    let settledPromises = [];
    let completedPromises = 0;

    promises.forEach((promise, index) => {
      Promise.resolve(promise)
        .then((result) => {
          settledPromises[index] = { status: 'fulfilled', value: result };
        })
        .catch((error) => {
          settledPromises[index] = { status: 'rejected', reason: error };
        })
        .finally(() => {
          completedPromises++;
          if (completedPromises === promises.length) {
            resolve(settledPromises);
          }
        });
    });
  });
}

模拟实现 instanceof

JavaScript 复制代码
function customInstanceof(obj, constructorFunc) {
  // 获取对象的原型
  let proto = Object.getPrototypeOf(obj);
  // 获取构造函数的原型
  let prototype = constructorFunc.prototype;

  // 循环向上查找原型链
  while (proto !== null) {
    // 如果找到了匹配的原型,则返回 true
    if (proto === prototype) {
      return true;
    }
    // 向上查找原型链
    proto = Object.getPrototypeOf(proto);
  }

  // 如果没有找到匹配的原型,则返回 false
  return false;
}

// 测试示例
function Person(name) {
  this.name = name;
}

let personObj = new Person('John');

console.log(customInstanceof(personObj, Person)); // 输出 true
console.log(customInstanceof(personObj, Object)); // 输出 true,因为所有对象都是Object的实例
console.log(customInstanceof(personObj, Array)); // 输出 false,因为personObj不是Array的实例

模拟实现 call、apply、bind

JavaScript 复制代码
// 模拟实现 call 方法
Function.prototype.customCall = function(context, ...args) {
  context = context || window;
  const fn = Symbol();
  context[fn] = this;
  const result = context[fn](...args);
  delete context[fn];
  return result;
};

// 测试示例
function greet(message) {
  return `${message}, ${this.name}!`;
}

const person = { name: 'John' };
console.log(greet.customCall(person, 'Hello')); // 输出 "Hello, John!"

// 模拟实现 apply 方法
Function.prototype.customApply = function(context, args) {
  context = context || window;
  const fn = Symbol();
  context[fn] = this;
  const result = context[fn](...args);
  delete context[fn];
  return result;
};

// 测试示例
function greet(message) {
  return `${message}, ${this.name}!`;
}

const person = { name: 'John' };
console.log(greet.customApply(person, ['Hello'])); // 输出 "Hello, John!"

// 模拟实现 bind 方法
Function.prototype.customBind = function(context, ...args) {
  const fn = this;
  return function(...innerArgs) {
    return fn.apply(context, args.concat(innerArgs));
  };
};

// 测试示例
function greet(message) {
  return `${message}, ${this.name}!`;
}

const person = { name: 'John' };
const boundGreet = greet.customBind(person, 'Hello');
console.log(boundGreet()); // 输出 "Hello, John!"

实现异步并发控制

JavaScript 复制代码
class AsyncQueue {
  constructor(concurrency) {
    this.concurrency = concurrency; // 最大并发量
    this.running = 0; // 当前并发量
    this.queue = []; // 任务队列
  }

  async run() {
    while (this.running < this.concurrency && this.queue.length > 0) {
      const task = this.queue.shift();
      this.running++;
      task().then(() => {
        this.running--;
        this.run();
      });
    }
  }

  add(task) {
    this.queue.push(task);
    this.run();
  }
}

// 使用示例
const asyncQueue = new AsyncQueue(2); // 最大并发量为2
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

function createTask(id, time) {
  return async () => {
    console.log(`Task ${id} started`);
    await delay(time);
    console.log(`Task ${id} finished`);
  };
}

asyncQueue.add(createTask(1, 2000)); // 添加任务1,执行时间为2000ms
asyncQueue.add(createTask(2, 1000)); // 添加任务2,执行时间为1000ms
asyncQueue.add(createTask(3, 1500)); // 添加任务3,执行时间为1500ms
asyncQueue.add(createTask(4, 500)); // 添加任务4,执行时间为500ms

千位分隔数 - leetcode#1556

TypeScript 复制代码
// 使用遍历常规解题
function thousandSeparator(n: number): string {
    const len = nums.length;
    // 处理长度不够三位的边缘场景
    if (len < 4) return ('' + n);
    // 转换为字符串
    const nums = ('' + n).split('').reverse();
    let res = '';
    while (nums.length) {
        const temp = nums.splice(0, 3).reverse();
        res = '.' + temp.join('') + res;
    }
    
    return res.startsWith('.') ? res.slice(1) : res;
};

// 技巧解题
function thousandSeparator(n: number): string {
    return n.toLocaleString().replaceAll(',', '.');
}

二叉树的层序遍历 - leetcode#102

TypeScript 复制代码
function levelOrder(root: TreeNode | null): number[][] {
    // 处理边缘场景
    if (!root) {
        return [];
    }
    
    let result = [];
    let queue = [root];
    // 对每一层做遍历
    while (queue.length > 0) {
        let level = [];
        let size = queue.length;
        
        for (let i = 0; i < size; i++) {
            let node = queue.shift();
            level.push(node.val);
            
            if (node.left) {
                queue.push(node.left);
            }
            
            if (node.right) {
                queue.push(node.right);
            }
        }
        
        result.push(level);
    }
    
    return result;
};

LRU 缓存 - leetcode#146

TypeScript 复制代码
class LRUCache {
    capacity;
    cacheMap;
    constructor(capacity: number) {
        this.capacity = capacity;
        this.cacheMap = new Map<number, number>();
    }

    get(key: number): number {
        const has = this.cacheMap.has(key);
        const value = this.cacheMap.get(key);
        if (has) {
            this.cacheMap.delete(key);
            this.cacheMap.set(key, value);
        }
        return has ? value : -1;
    }

    put(key: number, value: number): void {
        const size = this.cacheMap.size;
        const has = this.cacheMap.has(key);
        if (has) {
            this.cacheMap.delete(key);
            this.cacheMap.set(key, value);
        } else {
            if (size < this.capacity) {
                this.cacheMap.set(key, value);
            } else {
                this.cacheMap.delete([...this.cacheMap.keys()][0]);
                this.cacheMap.set(key, value);
            }
        }
    }
}

最长公共前缀 - leetcode#14

TypeScript 复制代码
function longestCommonPrefix(strs: string[]): string {
    const p = strs[0];
    let res = '';
    let i = 0;
    while (i < p.length) {
        const str = p[i];
        const has = strs.every((item) => item[i] === str);
        if (has) {
            res += str;
            i++;
        } else {
            return res;
        }
    }
    return res;
};

有效的括号 - leetcode#20

TypeScript 复制代码
function isValid(s: string): boolean {
    const left = ['(', '{', '['];
    const right = [')', '}', ']'];
    const com = ['()', '{}', '[]'];
    const stack: string[] = [];
    for (const str of s) {
        if (left.includes(str)) {
            stack.push(str);
        } 
        if (right.includes(str)) {
            const top = stack[stack.length - 1];
            if (com.includes(top + str)) {
                stack.pop();
            } else {
                return false;
            }
        }
    }
    return !stack.length;
};

三数之和 - leetcode#15

TypeScript 复制代码
function threeSum(nums: number[]): number[][] {
    const memory: string[] = [];
    const twoSum = (nums: number[], target: number) => {
        let i = 0;
        let j = nums.length - 1;
        nums.sort((a, b) => a - b);
        const res: number[][] = [];
        while(i < j) {
            const value1 = nums[i];
            const value2 = nums[j];
            const sum = value1 + value2;
            if (sum < target) i++;
            if (sum >= target) j--;
            if (sum === target) {
                i++;
                const temp = [value1, value2, 0 - target].sort((a, b) => a - b);
                const tempString = temp.join();
                if (!memory.includes(tempString)) {
                    res.push(temp);
                    memory.push(tempString);
                }
            }
        }
        return res;
    }
    const result: number[][] = [];
    for (const [key, val] of nums.entries()) {
        const temp = twoSum(nums.slice(key + 1), 0 - val);
        if (temp.length) result.push(...temp);
    }
    return result;
};

最小栈 - leetcode#155

TypeScript 复制代码
class MinStack {
    stackNums = [];
    constructor() {

    }

    push(val: number): void {
       this.stackNums.push(val);
    }

    pop(): void {
       return this.stackNums.pop();
    }

    top(): number {
       return this.stackNums[this.stackNums.length - 1];
    }

    getMin(): number {
       return Math.min(...this.stackNums);
    }
}

比较版本号 - leetcode#165

TypeScript 复制代码
function compareVersion(version1: string, version2: string): number {
    let versions1 = version1.split('.');
    let versions2 = version2.split('.');
    const len1 = versions1.length;
    const len2 = versions2.length;
    const len = Math.max(len1, len2);
    for (let i = 0; i < len; i++) {
        if (Number(versions1[i] || 0) > Number(versions2[i] || 0)) return 1;
        if (Number(versions1[i] || 0) === Number(versions2[i] || 0)) continue;
        if (Number(versions1[i] || 0) < Number(versions2[i] || 0)) return -1;
    }
    return 0;
};
相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax