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

前言

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

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

// 模拟实现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

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

// 模拟实现 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!"

实现异步并发控制

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

// 使用遍历常规解题
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

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

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

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

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

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

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

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;
};

原文链接:https://juejin.cn/post/7340535444986216511 作者:菩提谛听

(0)
上一篇 2024年2月29日 上午10:47
下一篇 2024年2月29日 上午10:57

相关推荐

发表回复

登录后才能评论