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

前言

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

模拟实现 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;
};
相关推荐
吃杠碰小鸡9 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone15 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
Serene_Dream33 分钟前
JVM 并发 GC - 三色标记
jvm·面试
xjt_090134 分钟前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king1 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳1 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_2 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js