【面试】秋招前端面试代码题记录

485 阅读5分钟

深圳抖音提前批一面

  • 二叉树的层序遍历
  • 节流

岛屿的周长

给定一个矩阵。矩阵的每个元素都是边长为 1 的正方形,值为 1 表示陆地,值为 0 表示海洋。相邻(上下左右)的陆地格子连成一个岛屿。假设矩阵中只有唯一的 1 个岛屿,求该岛屿的周长。 e.g.

输入:grid = [  [0,1,0,0],
  [1,1,1,0],
  [0,1,0,0],
  [1,1,0,0]
]
输出:16
输入:grid = [  [0,0,0,0],
  [0,1,0,0],
  [0,0,0,0],
  [0,0,0,0]
]
输出:4

我的解答(每个点的上下左右都是周长,如果有两个点相邻他们之间则没有周长需要减去):

function solve(grid) {
    let count = 0;
    let mianji = 0;
    grid.forEach((item, i) => {
        item.forEach((col, j) => {
            if(col === 1) {
                let up = i - 1;
                let left = j - 1;
                if(up >= 0 && grid[up][j] === 1) {
                    count++;
                }
                if(left >= 0 && grid[i][left] === 1) {
                    count++;
                }
                mianji++;
            }
        })
    })
    return mianji * 4 - count * 2;
}

深圳抖音提前批二面

es5实现数组去重

function solve(arr) {
    for(var i = 0; i < arr.length - 1; i++) {
        var item = arr[i];
        var remain = arr.slice(i + 1);
        if(remain.indexOf(item) > -1) {
            arr[i] = arr[arr.length - 1];
            arr.length--;
            i--;
        }
    }
}

链表重新排序

输入:123456,输出:162534

输入:12345...n,输出:1 n 2 n-1 3 n-2 ..

我的解答:

function solve(head) {
    if(!head || !head.next) return head;
    let fast = head;
    let slow = head;
    while(fast && fast.next) {
        fast = fast.next.next;
        slow = slow.next;
    }
    
    let currN = slow.next;
    let nextN = currN.next;
    let preN = slow;
    while(nextN) {
        currN.next = preN;
        preN = currN;
        currN = nextN;
        nextN = nextN.next;
    }
    
    let left = head;
    let right = currN;
    let newN = new Node(0);
    preN = newN;
    while(left !== right) {
        newN.next = new Node(left.val);
        newN = newN.next;
        newN.next = new Node(right.val);
        newN = newN.next;
    }
    return preN.next;
}

逻辑题

在岛上有100只老虎和1只羊,老虎可以吃草,但他们更愿意吃羊。

假设:

A:每次只有一只老虎可以吃羊,而且一旦他吃了羊,他自己就变成羊。

B:所有的老虎都是聪明而且完全理性的,他们的第一要务是生存,再能吃羊的时候,不介意自己变成羊。

问最后这只羊会不会被吃?如果是n只老虎和一只羊呢?

答:偶数只狼不会吃羊,奇数只狼会吃羊让狼数量回到偶数。

深圳抖音提前批三面

查找目标

给定一个数组,查找两个数,两个数相加等于一个数target,输出这两个的下标

我的解答:

function solve(arr, target) {
    const copyArr = [...arr];
    copyArr.sort((a, b) => a - b);
    let left = 0;
    let right = copyArr.length - 1;
    while(left < right) {
        const sum = copyArr[left] + copyArr[right];
        if (sum === target) {
            const indexL = arr.indexOf(copyArr[left]);
            const indexH = arr.lastIndexOf(copyArr[right]);
            return [indexL, indexH];
        } else if (sum < target) {
            right--;
        } else {
            left++;
        }
    }    
    return [-1, -1];
}

保证请求顺序返回

对于一个模糊匹配的搜索框,需要注意请求返回的顺序,怎样保证后发的请求返回结果不被先发请求返回的结果覆盖。

百度一面

统计二叉树有多少个值相同的节点

首先是输入一个二叉树的根节点,判断这个二叉树的所有节点的值是否都相等;而后升级为判断该二叉树是否有不少于num个的节点值相等。

我的解答:

function solve(node, count) {
  if (!node && !count) {
    return true;
  } else if (!node && count) {
    return false;
  }
  const dp = [node];
  const valMap = {};
  while (dp.length) {
    const curr = dp.shift();
    if (valMap[curr.val]) {
      valMap[curr.val] += 1;
    } else {
      valMap[curr.val] = 1;
    }
    if (valMap[curr.val] >= count) return true;
    if (curr.left) dp.push(curr.left);
    if (curr.right) dp.push(curr.right);
  }
  return false;
}

二维矩阵中的路径

输入一个二维矩阵,矩阵有0和1,0可以走1不能,求从矩阵左上角到矩阵右下角有没有一条由0组成的路线,有则返回true,无则返回false。

我的解答:

function solve(arr) {
  if (!arr || !arr.length || !arr[0].length ) return true;
  if (arr[0][0] === 1) return false;
  const isVisited = new Array(arr.length).fill(new Array(arr[0].length).fill(false));
  const stack = [{i: 0, j: 0}];
  const isEnable = (i, j) => {
    if (isVisited[i][j]) {
      return false;
    } else {
      isVisited[i][j] = true;
    }
    return i >= 0 && i < arr.length && j >= 0 && j < arr[0].length && arr[i][j] === 0;
  }
  while (stack.length) {
    const {i, j} = stack.pop();
    if (i === arr.length - 1 && j === arr[0].length - 1) {
      return true;
    }
    if (isEnable(i + 1, j)) {
      stack.push({i: i + 1, j});
    }
    if (isEnable(i, j + 1)) {
      stack.push({i, j: j + 1});
    }
    if (isEnable(i - 1, j)) {
      stack.push({i: i - 1, j});
    }
    if (isEnable(i, j - 1)) {
      stack.push({i, j: j - 1});
    }
  }
  return false;
}

猿辅导一面

节流函数

要求第一次就被触发,之后每time秒被触发,最后一次被触发一定要执行。

我的解答(没有实现最后一次触发的执行,可以结合防抖思考)

function throttle(func, wait) {
    let timer = null;
    let previous = 0;
    return function anonymous(... params) {
        let now = new Date();
        remaining = wait - (now - previous);
        if (remaining <= 0) {
            clearTimeout(timer);
            timer = null;
            previous = new Date();
            func.call(this, ...params);
        } else if(!timer){
            timer = setTimeout( _ => { 
                clearTimeout(timer);
                timer = null;
                previous = new Date();
                func.call(this, ...params);
            }, remaining);
        } 
    } 
}

层序遍历

二叉树 层序遍历 求叶子节点值的和

function solve(node) {
    let res = 0;
    const dp = [node];
    while(dp.length) {
        const curr = dp.shift();
        if (curr.left) {
            dp.push(curr.left);
        }
        if (curr.right) {
            dp.push(curr.right);
        }
        if (!curr.left && !curr.right) {
            res += curr.val;
        }
    }
    return res;
}

猿辅导二面

限制请求的发送

有一个请求数组,数组的每一个元素都是一个promise生成器,执行生成器则发送请求并返回一个promise,现在需要限制同时发送请求的数量为num个,并最大程度的利用这个num窗口,即保证同时都发送尽量多的请求,在所有请求结束后返回一个结果数组。

我的解答:

function solve (arr, num) {
    const index = 0;
    const resArr = [];
    return new Promise((resolve, reject) => {
        const newFunc = (arrItem, i) => {
            arrItem().then((data) => {
                resArr[i] = data;
            }, (err) => {
                resArr[i] = err;
            }).finally(() => {
                if (index < arr.length - 1) {
                    newFunc(arr[index]);
                    index++;
                } else if (index === arr.length - 1) {
                    resolve(resArr);
                }
            })
        }
        for (let i = 0; i < num; i++) {
            newFunc(arr[i], in);
        }
    });
}

美团一面

计算数学表达式字符串

计算 "-30+6/2-2*3" 的值,不考虑括号,不可使用eval

我的解答(笨办法,可以去查查更简单的思路)

function solve(str) {
    // 首先按符号分割字符串为数组,符号之间是数字
    const arr = [];
    let index = 0;
    let lastIndex = 0;
    while(index < str.length) {
        if (['+', '-', '*', '/'].includes(str[index])) {
            if (index > lastIndex) {
                arr.push(Number(str.substring(lastIndex + 1, index)));
            }
            arr.push(str[index]);
            lastIndex = index;
        }
        index++;
    }
    // 处理最后一个数字
    arr.push(Number(str.substring(lastIndex + 1, index)));
    
    // 先计算乘除法,用计算结果替代乘除法式子
    const newArr = [];
    let i = 0;
    while (i < arr.length) {
        let curr;
        if (arr[i] === '*') {
            curr = arr[i - 1] * arr[i + 1];
            newArr[newArr.length - 1] = curr;
            i = i + 2;
        } else if (arr[i] === '/') {
            curr = arr[i - 1] / arr[i + 1];
            newArr[newArr.length - 1] = curr;
            i = i + 2;
        } else {
            newArr.push(arr[i]);
            i++;
        }
    }
    
    // 最后计算加减法
    let res;
    let j;
    // 需要判断第一个数的符号
    if (['+', '-'].includes(newArr[0])) {
        res = newArr[0] === '+' ? newArr[1] : -1 * newArr[1];
        j = 2;
    } else {
        res = newArr[0];
        j = 1;
    }
    while(j < newArr.length) {
        if (newArr[j] !== '+' || newArr[j] !== '-') {
            res += newArr[j - 1] === '+' ? newArr[j] : -1 * newArr[j];
        } 
        j++;
    }
    return res;
}

二叉树中和为某一值的所有路径

输入一颗二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。备注:从树的根节点开始往下一直到叶子节点所经过的节点形成一条路径。

我的解答(深度遍历):

function solve(root, target) {
    const res = [];
    if (!root) return res;
    dfs(root, target, 0, [], res);
    return res;
}

function dfs(node, target, currSum, path, res) {
    currSum += node.val;
    
    path.push(node.val);
    if (currSum === target && node.left === null && node.right === null) {
        res.push(path.slice(0));
    }
    if (node.left) {
        dfs(node.left, target, currSum, path, res);
    }
    if (node.right) {
        dfs(node.right, target, currSum, path, res);
    }
    
    path.pop();
}

美团二面

二叉树的前序遍历

/*
 * function TreeNode(x) {
 *   this.val = x;
 *   this.left = null;
 *   this.right = null;
 * }
 */

/**
  * 
  * @param root TreeNode类 
  * @return int整型一维数组
  */
function preorderTraversal( root ) {
    const res = [];
    const stack = [root];
    if (!root) return res;
    while (stack.length) {
        const curr = stack.pop();
        if (curr.right) stack.push(curr.right);
        if (curr.left) stack.push(curr.left);
        res.push(curr.val);
    }
    return res;
}
module.exports = {
    preorderTraversal : preorderTraversal
};

腾讯企业微信一面

函数节流的实现

function throttle(func, wait) {
    let timer = null;
    let previous = 0;
    return function anonymous(...params) {
        let now = Date.now();
        let remaining = wait - (now - previous);
        if (remaining <= 0) {
            clearTimeout(timer);
            timer = null;
            previous = Date.now();
            func.call(this, ...params);
        } else if (!timer) {
            timer = setTimeout(() => {
                timer = null;
                previous = Date.now();
                func.call(this, ...params);
            }, remaining);
        }
    }
}

打平的数据结构转成一棵树

将一个打平的数据结构转成一棵树,比如:

let arr = [
   {id: 1, name: '部门1', pid: 0}, 
   {id: 2, name: '部门2', pid: 1}, 
   {id: 3, name: '部门3', pid: 5}, 
   {id: 4, name: '部门4', pid: 1},
   {id: 5, name: '部门5', pid: 4},
]

转换后:
[ 
 {
   "id": 1, 
   "name": "部门1”,
   "pid": 0, 
   "children”:
    [
         { 
            "id": 2, 
            "name": "部门2”,
            "pid": 1, 
            "children": []
         },
         { 
           "id": 4, 
           "name": "部门4”, 
           "pid": 1, 
           "children": [{
                "id": 5, 
                "name": "部门5”,
                "pid": 1, 
                "children": [ ...... ]
            }]
        }
   ] }
]

我的解答:

  function arrayToTree(arr) {
    const map = {};
    const res = [];
    for(let item of arr) {
      const {id, pid} = item;
      if (!map[id]) {
        map[id] = {
          children: [],
        }
      }
      map[id] = {
        ...item,
        children: map[id].children,
      }

      if (pid === 0) {
        res.push(map[id]);
      } else {
        if (!map[pid]) {
          map[pid] = {
            children: [],
          }
        }
        map[pid].children.push(map[id]);
      }
    }
    return res;
  }

分割整数数组

给你一个整数数组 A,在不改变顺序的情况下将其划分为三个和相等的非空部分时才返回分割的位置下标,否则返回 false

[1,2,3,6,8,-1,-1]
结果:[2,3]

我的解答:

  function solve(arr) {
    let sum = 0;
    for(let item of arr) {
      sum += item;
    }
    if (sum % 3 !== 0) {
      return false;
    }

    const res = [];
    let subSum = 0;
    for(let i = 0; i < arr.length; i++) {
      subSum += arr[i];
      if (res.length === 2) {
        return res;
      }
      if (subSum === sum / 3) {
        res.push(i);
        subSum = 0;
      }
    }
    return false;
  }

快手一面

看代码:作用域、原型链

// 0
var count = 10;
function a() {
   return count + 10;
}
function b() {
   var count = 20;
   return a();
}
console.log(b());

//1
Function.prototype.a = () => console.log(1);
Object.prototype.b = () => console.log(2);
function A() {};
A.prototype.c = () => console.log(3);\
var a = new A();
a.a();
a.b();
a.c();

// 2
function Foo() {
 this.a = 1;
 return {
   a: 4,
   b: 5,
 };
}

Foo.prototype.a = 6;
Foo.prototype.b = 7;
Foo.prototype.c = 8;
var o = new Foo();
console.log(o.a);
console.log(o.b);
console.log(o.c);

 o = {
   a: 4,
   b: 5,
 }

分割线线转驼峰

function kebabToCamelCase() {}
kebabToCamelCase('get-element-by-id')

'aa'.toUpperCase() // 'AA'

我的答案:

function kebabToCamelCase(str) {
    if (!str) return str;
    const arr = str.split('-');
    for (let i = 1; i < arr.length; i++) {
        arr[i] = arr[i][0].toUpperCase() + arr[i].substring(1);
    }
    return arr.join('');
}

进制转换

function toBase(m, n) {}

toBase(100, 2) // 1100100
toBase(10, 3) // 101

m是一个十进制的数
n是从2-9整数
toString

我的答案:

function toBase(m, n) {
    if (n > 9 || n < 2) return null;
    let remain = 0;
    const stack = [];
    while (m > 0) {
        remain = Math.floor(m % n);
        stack.unshift(remain);
        m = Math.floor(m / n);
    }
    return stack.join('');
}

二维查找

function findX(matrix, target) {}

var matrix =
[
[0, 3, 6, 9, 12],
[5, 10, 15, 20, 25],
[7, 14, 21, 28, 35],
[11, 22, 33, 44, 55],
[13, 26, 39, 52, 65]
]
findX(matrix, 20) // [1, 3]
findX(matrix, 99) // [-1, -1]

n * n
从左到右由小变大,从上到下由小变大

我的答案:

function findX(matrix, target) {
    if (!matrix || !matrix.length) return [-1, -1];
    let i = matrix.length - 1;
    let j = 0;
    while(i > -1 && j < matrix[0].length) {
        if (matrix[i][j] === target) {
            return [i, j];
        } else if (target < matrix[i][j]) {
            i--;
        } else {
            j++;
        }
    }
    return [-1, -1];
}

快手二面

发布订阅

我的答案:

class Solve {
    constructor() {
        this.events = {};
    }
    
    on(event, callback) {
        if (!this.events[event]) {
            this.events[event] = [callback];
        } else {
            this.events[event].push(callback);
        }
    }
    
    emit(event) {
        this.events[event] && this.events[event].forEach((cbFn) => cbFn());
    }
}