前端面试经典算法题
前言
现在面试流行考核算法,做过面试官,也被面试。问算法对面试官来说,是一种解脱,找出了一个看似很高明且能偷懒的办法选择人,避免了不知道问啥的尴尬;被面试者,也找到了一种新的面试八股文,刷就对了;算法题让面试与被面试找到了一种平衡。
在实际的开发中,很多被考核的算法确实没啥卵用,面试者要认真琢磨考什么?下面是作者本人经历的一些面试题,有字节、腾讯、百度、滴滴的,仅供参考。
字符串插值
考察正则表达式、数组、字符串操作
// 字符串插值;
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));
你要觉得这篇文章比较好,记得点推荐!