前端面试经典算法题

前言

现在面试流行考核算法,做过面试官,也被面试。问算法对面试官来说,是一种解脱,找出了一个看似很高明且能偷懒的办法选择人,避免了不知道问啥的尴尬;被面试者,也找到了一种新的面试八股文,刷就对了;算法题让面试与被面试找到了一种平衡。

在实际的开发中,很多被考核的算法确实没啥卵用,面试者要认真琢磨考什么?下面是作者本人经历的一些面试题,有字节、腾讯、百度、滴滴的,仅供参考。

字符串插值

考察正则表达式、数组、字符串操作

// 字符串插值;
const data1 = {
  asd: {
    ddd: ["bbb"],
  },
};
const data2 = {
  ccc: 666,
};
const template = (str, data) => {
  // 正则匹配
  // ${data.asd.ddd.0}
  const reg = /${(.+[^}])}/g;
  const tempStr = str.match(reg)[0].replace("${data.", "").replace("}", "");
  console.log(tempStr);

  let arr = tempStr.split(".");

  // 第0个赋值
  let resTemp = data[arr[0]];

  // 遍历查询
  for (let i = 1; i < arr.length; i++) {
    if (resTemp[arr[i]]) {
      resTemp = resTemp[arr[i]];
    } else {
      resTemp = undefined;
    }
  }
  let res = resTemp;

  // 数组转换
  if (res !== undefined) {
    res = Array.from(new Set(resTemp.split(""))).join("");
  }
  return str.replace(reg, res);
};

console.log(template("pre_${data.asd.ddd.0}_tail", data1));

// pre_b_tail;

// console.log(template("pre_${data.ccc}_tail", data2));

// pre_666_tail;

将一组区间中所有重叠的区间进行合并

例如 // 输入:[[1,3],[2,6],[10,15],[9,11],[1,3]] // 输出:[ [ 1, 6 ], [ 9, 15 ] ]

不知道考核什么,可能是考核逻辑(需要脑子清醒的时候面~)

function mergeArr(arr) {
  //   arr = Array.from(new Set(arr));
  //   console.log(arr);
  //   arr = ar.map((item) => {});
  const res = [arr[0]];

  for (let i = 1; i < arr.length; i++) {
    const ele1 = arr[i];
    let count = 0;
    for (let j = 0; j < res.length; j++) {
      const ele2 = res[j];
      if (ele1[0] >= ele2[0] && ele1[0] <= ele2[1] && ele1[1] >= ele2[1]) {
        ele2[1] = ele1[1];
      } else if (
        ele1[1] >= ele2[0] &&
        ele1[1] <= ele2[1] &&
        ele1[0] <= ele2[0]
      ) {
        ele2[0] = ele1[0];
      } else {
        count++;
      }
    }
    if (count === res.length) {
      res.push(ele1);
    }
  }
  console.log(res);
  return res;
}

mergeArr([
  [1, 3],
  [2, 6],
  [10, 15],
  [9, 11],
  [1, 3],
]);

b中存在多少个a中的字符串

考核的是Map用法

// a生成has map,查询b的字符串是否存在map中
function str(a, b) {
  const map = new Map();
  let res = 0;
  // a转为map
  for (let i = 0; i < a.length; i++) {
    map.set(a[i], 0);
  }
  // 对b进行遍历,查看map中是否存在b[j]
  for (let j = 0; j < b.length; j++) {
    if (map.has(b[j])) {
      res++;
      // map.set(b[j], map.get(b[j] + 1));
    }
  }
  return res;
}

const J = "aA";
const S = "aAAbbbbb";

console.log(str(J, S));

考察十进制转二进制

/**************** 题目***********/
// 输⼊: 5
// 输出: 2
// 解释: 5 的⼆进制表示为 101(没有前导零位),其补数为 010。所以你需要输出 2 。

// 输⼊: 1
// 输出: 0
// 解释: 1 的⼆进制表示为 1(没有前导零位),其补数为 0。所以你需要输出 0 。
/**************** 题目***********/

// 字符串使用索引只能读不能改
// replace方法只能不修改字符串本身
// 二进制 十进制转换

function fn(n) {
  let str = parseInt(n).toString(2);

  if (str[0] === "1") {
    str = "0" + str.slice(0, str.length - 1);
  } else {
    str = "1" + str.slice(0, str.length - 1);
  }

  return parseInt(str, 2);
}
console.log(fn(5));

// 有符号右位移;
function fn2(n) {
  return n >> 1;
}
console.log(fn2(5));

首个不重复字符索引

// 首个不重复字符串索引
function fn(str) {
  const map = new Map();
  for (let i = 0; i < str.length; i++) {
    if (map.has(str[i])) {
      map.set(str[i], 1);
    } else {
      map.set(str[i], 0);
    }
  }

  for (let i = 0; i < str.length; i++) {
    if (map.get(str[i]) === 0) {
      return i;
    }
  }
  return -1;
}

console.log(fn("loveleetcode"));

数组排序

function fn(arr1, arr2) {
  let temp = 0;
  let res = arr2;
  while (arr1.length) {
    const num = arr1.shift();

    for (let i = temp; i < arr2.length; i++) {
      if (num <= arr2[i]) {
        // res = [num].concat(res);
        res.splice(i, 0, arr2[i]);
        temp = i;
        break;
      }
    }
  }
  console.log(res);
  return res;
}

fn([1, 3, 4], [1, 2, 3, 4, 5]);

数组中两个数的和

// 数组加和
function fn(arr, target) {
  const len = arr.len;
  const res = [];
  const map = new Map();

  arr.forEach((item) => {
    const temp = target - item;
    if (map.has(temp)) {
      res.push([item, map.get(temp)]);
    }
    map.set(item, item);
  });

  console.log(res);
  return res;
}

const arr = [15, 2, 7, 3, 11, 1];
const target = 18;
fn(arr, target);

// 输出[(3, 15)][(7, 11)];

n 个有序数组,求第m大的数

// n 个有序数组,求第m大的数
function fn(arr, m) {
  // 数组合并
  for (let i = 0; i < arr.length - 1; i++) {
    const arr1 = arr[i];
    const arr2 = arr[i + 1];

    while (arr1.length) {
      const n = arr1.shift();
      for (let j = 0; j < arr2.length; j++) {
        if (n <= arr2[j]) {
          arr2.splice(j, 0, n);
          break;
        }
      }
    }
  }

  console.log(arr[arr.length - 1], arr[arr.length - 1][m - 1]);

  return arr[arr.length - 1][m - 1];
}

fn(
  [
    [1, 2, 3],
    [2, 3, 5],
  ],
  3
);

无序数组。有正有负,求和最大的子数组

// 无序数组。有正有负,求和最大的子数组

function fn(arr) {
  // 子数组
  const len = arr.length;
  arr = arr.map((item) => {
    if (item >= 0) return item;
  });

  console.log(arr);
  const subArr = [];

  const backtrack = (path, l) => {
    if (path.length === l) {
      subArr.push(path);
      return;
    }
    for (let i = 0; i < len; i++) {
      if (path.includes(arr[i])) continue;
      backtrack(path.concat([arr[i]]), l);
    }
  };

  for (let i = 1; i <= len; i++) {
    backtrack([], i);
  }

  subArr.sort((a, b) => {
    // console.log(a);
    const aSum = a.reduce((p, n) => p + n);
    const bSum = b.reduce((p, n) => p + n);
    return bSum - aSum;
  });
  console.log(subArr[0]);

  return subArr[0];
  //     for (let n = 0; n < subArr.length; n++) {
  //         const mid = Math.floor(subArr.length / 2)

  //   }

  // 和比较
}

fn([1, 2, -3]);

闭包&函数的toString方法

// add(1)(2)(3) 6
// add(1)(2)(3)(4) 10

function add() {
  // 保存变量
  let arg = [].slice.call(arguments);
  // 加和计算

  function _adder() {
    const _arg = [].slice.call(arguments);
    arg.push(..._arg);
    console.log(_arg);

    _adder.toString = function() {
      const res = arg.reduce((previous, current) => {
        return previous + current;
      });

      return res;
    };
    return _adder;
  }

  return _adder;
}

const a = add(1, 2)(3);
console.log(a + 1);

字符串的随机组合

// 字符串的随机组合

// 回溯算法

function randomStr(str) {
  const res = [];

  const backtrack = (path) => {
    if (path.length === str.length) {
      res.push(path);
      return;
    }
    for (let i = 0; i < str.length; i++) {
      if (path.includes(str[i])) continue;
      backtrack(path + str[i]);
    }
  };

  backtrack("", 0);
  console.log(res);
  return res;
}

randomStr("abc");

平衡二叉树

// 平衡二叉树

function isBalanced(root) {
  if (!root) return true;

  const rec = (root) => {
    if (!root) return true;
    const left = root.left;
    const right = root.right;
    const leftValue = rec(left);
    const rightValue = rec(right);
    if (
      leftValue.left === null &&
      leftValue.right === null &&
      (rightValue.right.right || rightValue.right.left)
    ) {
      return false;
    }

    if (
      rightValue.left === null &&
      rightValue.right === null &&
      (rightValue.right.right || rightValue.right.left)
    ) {
      return false;
    }
  };

  rec(root);
}

console.log(isBalanced(bt));

大数阶乘算法

因为数大,js是存不下的,因此就把计算结果拆解存数组里面,原理就是把计算的各个位的值存起来。

function fn(n){
  let a = [1]
  for(let i = 1; i <= n; i++) {
    // res*=i
     for(let j = 0, c = 0; j < a.length || c != 0; j++){
         const m = (j < a.length) ? (i * a[j] + c) : c
         a[j] = m % 10
         c = (m - a[j])/10
    }
  }
  return a.reverse().join('')
}
console.log(fn(1005));
posted @ 2023-08-05 21:05  地铁程序员  阅读(53)  评论(0编辑  收藏  举报