前言
哈喽啊兄弟们,经历了这么久的面试沉淀,我吧目前面试遇到的经典考题进行了一波总结,希望可以对同在路上的伙伴们一些帮助。都是很简单的面试题,我就直接给出答案了。
快速排序
const arr = [5, 2, 7, 8, 34, 7, 39, 12, 56, 9, 1];
// 期望效果
// [1, 2, 5, 7, 7, 8, 9, 12, 34, 39, 56];
思路: 递归。
function quickSort(arr) {
// 如果个数小于2,直接返回。
if (arr.length <= 2) return arr;
// 获取中间的数字
const midIndex = Math.floor(arr.length / 2);
const midNum = arr.splice(midIndex, 1)[0];
const leftArr = [],
rightArr = [];
// 进行比较,比中间的数字小则加入leftArr,反之加入rightArr。
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if (item < midNum) {
leftArr.push(item);
} else {
rightArr.push(item);
}
}
// 递归调用直到顺序完全正确。将他们拼合在一起。
return quickSort(leftArr).concat(midNum, quickSort(rightArr));
}
二分查找
const nums = [1,2,3,4,5,6,7,8,9];
console.log(search(nums, 4));
// 期望结果: 3
思路: 猜数字游戏,猜中间数来最大程度的缩小范围,以便更快的找到数字。
function search(nums, target) {
let left = 0,
right = nums.length;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
console.log(mid,nums[mid]);
if (target > nums[mid]) {
left = mid + 1;
} else if (target < nums[mid]) {
right = mid - 1;
} else {
return mid;
}
}
}
柯里化
var add = function (num1, num2) {
return num1 + num2;
};
var sum = curry(add);
console.log(sum(4)(3)(2)(1)(5)());
// 15
思路:
var add = function (num1, num2) {
return num1 + num2;
};
function curry(add) {
var arr = [];
return function reply() {
var arg = Array.prototype.slice.call(arguments);
arr = arr.concat(arg);
console.log('arg',arg,arr);
if (arg.length === 0) {
return arr.reduce(function (p, c) {
return (p = add(p, c));
}, 0);
} else {
return reply;
}
};
}
var sum = curry(add);
console.log(sum(4)(3)(2)(1)(5)());
扁平化
let obj = {
a: {
b: "a-b",
},
c: "ccc",
d: {
e: {
f: "fff",
},
},
};
console.log(flat(obj));
// { 'a.b': 'a-b', c: 'ccc', 'd.e.f': 'fff' }
思路:
function flat(obj, tar = {}, keyName) {
let _keyName = keyName ? keyName : "";
for (let k in obj) {
let name = _keyName ? _keyName + "." + k : k;
if (typeof obj[k] === "object") {
flat(obj[k], tar, name);
} else {
tar[name] = obj[k];
}
}
return tar;
}
LazyMan
let X = LazyMan("xicongbo");
X.eat("早餐").sleep(6).eat('晚餐');
// xicongbo
// 早餐
// 等待6s之后
// 晚餐
思路:
class LazyManClass {
constructor(name) {
this.name = name;
this.tasks = [];
setTimeout(() => {
console.log(name);
this.next();
});
}
next() {
let fn = this.tasks.shift();
fn && fn();
}
eat(food) {
let task = () => {
setTimeout(() => {
console.log(food);
this.next();
});
};
this.tasks.push(task);
return this;
}
sleep(time) {
let task = () => {
setTimeout(() => {
console.log(time);
this.next();
}, time * 1000);
};
this.tasks.push(task);
return this;
}
}
function LazyMan(name) {
return new LazyManClass(name);
}
EventBus
const eventBus = new EventBus();
// 订阅事件eventX
eventBus.subscribe("eventX", (obj, num) => {
console.log("模块A", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("模块B", obj, num);
});
eventBus.subscribe("eventX", (obj, num) => {
console.log("模块C", obj, num);
});
// 发布事件eventX
eventBus.publish("eventX", { msg: "EventX published!" }, 1);
//模块A { msg: 'EventX published!' } 1
//模块B { msg: 'EventX published!' } 1
//模块C { msg: 'EventX published!' } 1
思路:
class EventBus {
constructor() {
this.eventObj = {};
this.eventId = 0;
}
publish(eventName, ...args) {
let callbackList = this.eventObj[eventName];
for (let id in callbackList) {
callbackList[id](...args);
}
}
subscribe(eventName, callback) {
if (!this.eventObj[eventName]) {
this.eventObj[eventName] = {};
}
let id = this.eventId++
this.eventObj[eventName][id] = callback;
const unSubscribe = function () {
delete this.eventObj[eventName][id];
};
return {unSubscribe};
}
}
const eventBus = new EventBus();
节流和防抖(简易版本)
function debounce(fn, delay) {
let timeOut = null;
return function () {
if (timeOut) clearTimeout(timeOut);
timeOut = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
function throttle(fn, delay) {
let flag = true;
return function () {
if (!flag) return;
flag = false;
setTimeout(() => {
fn.apply(this, arguments);
flag = true;
}, delay);
};
}
cloneDeep
function cloneDeep(obj) {
let newObj = {};
for (let k in obj) {
let tempData = typeof obj[k] === "object" ? flat(obj[k]) : obj[k];
newObj[k] = tempData;
}
return newObj;
}
括号匹配问题
console.log(isVaild('()()(){{[[]]}}'));
// true
console.log(isVaild('()()(}}}'));
// false
思路: 栈
const isVaild = (s) => {
let leftToRight = {
"(": ")",
"[": "]",
"{": "}",
};
let stack = [];
for (let i = 0; i < s.length; i++) {
let c = s[i];
if (leftToRight[c]) {
stack.push(c);
} else if (!c.length || leftToRight[stack.pop()] !== c) {
return false;
}
}
return !stack.length;
};
简易版计算器
console.log(calculate("1+3*4/2-5"));
// 2
思路: 栈,本题偏难,主要思路为,将乘除法的结果直接运算出来并推入栈中,最后统一进行加法。
function calculate(s) {
let sign = "+",
n = 0,
c,
stack = [];
for (let i = 0; i < s.length; i++) {
c = s.charAt(i);
if (c <= 9 && c >= 0) {
n = n * 10 + parseInt(c);
if (i < s.length - 1) continue;
}
if (sign == "+") {
stack.push(n);
} else if (sign == "-") {
stack.push(-n);
} else if (sign == "*") {
stack.push(stack.pop() * n);
} else if (sign == "/") {
stack.push(Math.trunc(stack.pop() / n));
}
sign = c;
n = 0;
}
let res = stack.reduce((a, b) => a + b, 0);
return res;
}