阅读 841

金九银十大厂前端面经

滴滴

实现一个returnType

type MyReturnType<T> = T extends (...args)=> infer P ? P : never;
复制代码

实现一个react 防抖自定义hook

function useDebounce(fn, delay = 100) {
  const ref = useRef(fn);
  ref.current = function () {
    let timer;
    return function () {
      const context = this;
      const args = arguments;
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      timer = seTimeout(fn.apply(context, args), delay)
    }
  }
  return ref.current;
}
复制代码

力扣 二叉树中的最大路径和

function findMaxPath(node) {
  let maxVal = -Infinity;
  function findMaxPath(node) {
    if (!node) return 0;
    const leftVal = Math.max(findMaxPath(node.left), 0);
    const rightVal = Math.max(findMaxPath(node.right), 0);
    const ps1 = node.val + Math.max(leftVal, rightVal);
    const ps2 = node.val + leftVal + rightVal;
    maxVal = Math.max(...[maxVal, ps1, ps2]);
    return ps1;
  }
  findMaxPath(node);
  return maxVal;
}
复制代码

数字转换

写出一个函数trans,将数字转换成汉语的输出,输入为不超过10000亿的数字。

例如:trans(123456) —— 十二万三千四百五十六

trans(100010001)—— 一亿零一万零一

let numChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
let numUnit = ['', '十', '百', '千'];
let numSection = ['', '万', '亿', '万亿', '亿亿'];

// 将数字映射成中文
function formatSection(num) {
  let arr = (num + '').split('').reverse();
  let str = '';
  for (let i = 0; i < arr.length; i++) {
    let char = arr[i] === 0 ? numChar[0] : numChar[arr[i]] + numUnit[i];
    str = char + str;
  }
  let s = str.replace(/零+/g, '零').replace(/零+$/, '');
  return s;
}

// 将字符串按个数拆分
function formatNum(num, str) {
  let len = Math.ceil(str.length / num);
  let arr = [];
  let reverseStr = str.split('').reverse().join('');
  for (let i = 0; i < len; i++) {
    let result = reverseStr
      .slice(i * num, i * num + 4)
      .split('')
      .reverse()
      .join('');
    arr.unshift(result);
  }
  return arr;
}

function numberTranToCN(num) {
  let arr = formatNum(4, num + '');
  let list = [];
  for (let i = 0; i < arr.length; i++) {
    let str = formatSection(arr[i]);
    list.push(str);
  }
  let reverseList = list.reverse();
// 补上区间单位
  for (let j = 0; j < reverseList.length; j++) {
    reverseList[j] += numSection[j];
  }
  return reverseList.reverse().join('');
}

console.log(numberTranToCN(12345));
console.log(numberTranToCN(1000003));
复制代码

去除字符串中出现次数最少的字符,不改变原字符串的顺序

例1:“ababac” —— “ababa”

例2:“aaabbbcceeff” —— “aaabbb”

function task(str) {
  let min = Infinity;
  let map = new Map();
  
  for (let i = 0; i < str.length; i++) {
    const count = (map.get(str[i]) ?? 0) + 1;
    map.set(str[i], count);
  }

  min = Math.min(...map.values());

  return str.split('').reduce((pre, cur) => {
    if (map.get(cur) === min) {
      return pre;
    } else {
      return pre + cur;
    }
  }, '');
}
复制代码

字节跳动

剑指 Offer II 103. 最少的硬币数目

79. 单词搜索

脉脉

手写一个usePrevious

function usePervious(newValue) {
  const pre = useRef();
  const cur = useRef();
  pre.current = cur.current;
  cur.current = newValue;
  return pre;
}
复制代码

原型链

console.log(Function.__proto__ === Function.prototype);
//Function是一台制造机器的机器
console.log(Object.__proto__ === Function.prototype);
console.log(Function.prototype.__proto__ === Object.prototype);
复制代码

手写一个深比较

function compareObj(obj1, obj2) {
  if (typeof obj1 !== 'object' && typeof obj2 !== 'object') {
    return obj1 === obj2;
  }

  if (
    Array.isArray(obj1) &&
    Array.isArray(obj2) &&
    obj1.length === obj2.length
  ) {
    let result;
    for (let key in obj1) {
      result = compareObj(obj1[key], obj2[key]);
      if (!result) {
        return false;
      }
    }
    return true;
  }

  if (Object.keys(obj1).length === Object.keys(obj2).length) {
    if (Object.is(obj1, obj2)) return true;
    let result;
    let diff = true;
    Object.keys(obj1).forEach((key) => {
      result = compareObj(obj1[key], obj2[key]);
      if (!result) {
        diff = false;
      }
    });
    return diff;
  }
  return false;
}

console.log(compareObj(1, 1));
console.log(compareObj([1], [1]));
console.log(compareObj([1], [1,2]));
console.log(compareObj({ name: 123 }, { name: 123 }));
复制代码

算法题

在一个长度为 n+1 的数组里的所有数字都在 1~n 的范围内,所以数组 中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能 修改输入的数组。例如,如果输入长度为8 的数组「2,3,5,4,3,2,6,7」,那么 对应的输出是重复的数字2 或者3

function task(numbs) {
  for (let i = 0; i < numbs.length; i++) {
    const k = numbs[i];
    const j = numbs[k];
    if (k === j) {
      return k;
    } else {
      [numbs[i], numbs[k]] = [numbs[k], numbs[i]];
    }
  }
}

console.log(task([2, 3, 5, 4, 3, 2, 6, 7]));
复制代码

二分查找

给定一个有序(非降序)数组A,可能含有重复元素,求最小的i使得A[i]等于target,不存在则返回-1。

array =[1,2,3,5,6,7,7,10]

target = 7,return 5

target = 8, return -1

function task(arr, target) {
  if (!arr || arr.length === 0) return -1;
  let left = 0,
    right = arr.length;
  while (left < right) {
    const mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) {
      for (let i = mid; i > 0; i--) {
        if (arr[i] === target && arr?.[i - 1] !== target) {
          return i;
        }
      }
    } else if (arr[mid] > target) {
      right = mid - 1;
    } else {
      left = mid + 1;
    }
  }
  return -1;
}

console.log(task([1, 2, 3, 5, 6, 7, 7, 10], 7));
console.log(task([1, 2, 3, 5, 6, 7, 7, 10], 8));
复制代码

算法题

347. 前 K 个高频元素

var topKFrequent = function (nums, k) { 
    const map = new Map(); 
    for (let i = 0; i < nums.length; i++) { 
        map.set(nums[i], (map.get(nums[i]) ?? 0) + 1) 
    } 
    return Array.from(map).sort((a, b) => b[1] - a[1]).slice(0, k).map(item => item[0]) 
};
复制代码

蚂蚁金服

William 链式调用 宏任务 微任务

class PersonReal {
  constructor(name) {
    this.name = name;
    this.taskQueue = [];
    this.taskIsRunning = false;

    function task(name) {
      console.log(`Hi! This is ${name}!`);
    }
    this.taskQueue.push(task.bind(this, name));
    this._runQueue();
  }

  eat(food) {
    const task = (food) => {
      console.log('Eat ' + food + '~');
    };
    this.taskQueue.push(task.bind(this, food));
    this._runQueue();
    return this;
  }

  sleep(time) {
    const task = new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log(`Wake up after ${time}`);
        resolve();
      }, time * 1000);
    });
    this.taskQueue.push(task);
    this._runQueue();
    return this;
  }

  sleepFirst(time) {
    const task = new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log(`Wake up after ${time}`);
        resolve();
      }, time * 1000);
    });
    this.taskQueue.unshift(task);
    this._runQueue();
    return this;
  }

  _runQueue() {
    if (this.taskIsRunning) return;
    this.taskIsRunning = true;

    const goNext = () => {
      if (this.taskQueue.length) {
        let task = this.taskQueue.shift();
        if (task.then) {
          task.then(() => {
            goNext();
          });
        } else {
          task();
          goNext();
        }
      } else {
        this.taskIsRunning = false;
      }
    };
    Promise.resolve().then(() => {
      goNext();
    });
  }
}

function Person(name) {
  return new PersonReal(name);
}
复制代码

网易 灵犀事业部

ts题

type DeepReadonly<T extends Record<string, any>> = {
  readonly [K in keyof T]: T[K] extends Record<string, any>
    ? DeepReadonly<T[K]>
    : T[K];
};
复制代码

提取并拼接一个Object下的所有字符串, 且不超过50长度

// 输入:
const input = {
  a1: '标题1',
  b2: '标题2',
  x3: {
    d: '段落1',
    m: 12,
    k: true,
    c7: {
      s: 'abc',
      k: [],
    },
  },
};

function getSummary(object) {
  let result = '';
  if (Object.keys(object).length === 0) return result;

  const task = (obj) => {
    for (let key in obj) {
      if (typeof obj[key] === 'string') {
        const resultLen = result.length;
        const canAdd = resultLen + obj[key].length <= 50;
        if (canAdd) {
          result += obj[key];
        }
      } else {
        task(obj[key])
      }
    }
  };

  task(object);
  return result;

}
console.log(getSummary(input));
// 输出:
// '标题1标题2段落1abc'
复制代码

未完待续

文章分类
前端
文章标签