FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

一些特别棒的面试题[4] #245

Open FrankKai opened 3 years ago

FrankKai commented 3 years ago

最近面试了一些公司,拿了一些offer,不记录概念题目,仅记录coding类题目。 小伙伴们空闲时间可以做这些题目练练手。​

FrankKai commented 3 years ago

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
答案 ```js /** * @param {number[]} nums * @return {number} */ var singleNumber = function (nums) { /** 解法1:暴力遍历 * 性能:704ms 40.5MB */ let numsSet = Array.from(new Set(nums)); let numsMap = numsSet.map((num) => ({ num, count: 0, })); nums.forEach((num, i) => { numsMap.forEach((numM, j) => { if (numM.num === num) { numM.count++; } }); }); let filterArr = numsMap.filter((num) => num.count === 1); return filterArr[0].num; /** 解法2:Set 首次出现add 二次出现delete * 性能: 72 ms 38MB */ let numsSet = new Set(); for (let i = 0; i < nums.length; i++) { if (!numsSet.has(nums[i])) { numsSet.add(nums[i]); } else { numsSet.delete(nums[i]); } } return [...numsSet][0]; }; ``` 这是一道leetcode 简单难度的题。 题目:[leetcode 136 只出现一次的数字](https://leetcode-cn.com/problems/single-number/) 题解:[136 只出现一次的数字](https://github.com/FrankKai/leetcode-js/blob/master/136.Single_Number.js)
FrankKai commented 3 years ago

汇总区间

给定一个乱序整形数组[0,1,7,13,15,16,2,4,5],找出其中连续出现的数字区间为如下:["0->2", "4->5", "7", "13", "15->16"]
答案 ```js function continuous(arr) { arr.sort((a, b) => a - b); let stack = []; let result = []; for (let i = 0; i < arr.length; i++) { if (stack.length === 0 || arr[i] - stack[stack.length - 1] === 1) { stack.push(arr[i]); } else { if (stack.length > 1) { result.push(`${stack[0]}->${stack[stack.length - 1]}`); } else { result.push(`${stack[0]}`); } stack = []; stack.push(arr[i]); } if (i === arr.length - 1) { if (stack.length > 1) { result.push(`${stack[0]}->${stack[stack.length - 1]}`); } else { result.push(`${stack[0]}`); } } } return result; } console.log(continuous([0, 1, 7, 13, 15, 16, 2, 4, 5])); ``` 这是一道leetcode 中等难度的题。 题目:[leetcode 228 汇总区间](https://leetcode-cn.com/problems/summary-ranges/) 题解:[228汇总区间(Summary Ranges)](https://github.com/FrankKai/leetcode-js/blob/master/228.Summary_Ranges.js)
FrankKai commented 3 years ago

实现红绿灯效果

实现红绿灯效果,使用console 输出 “红”、“绿”、“黄”示意,等待时间分别为 3s、2s、1s
答案 ```js function trafficCtrl() { // timeline 红0~2 绿3~4 黄5 const borders = { red: 3, green: 5, yellow: 6 }; let current = 0; setInterval(() => { if (current >= 0 && current <= 2) { console.log('红', borders.red - current); } else if (current >= 3 && current <= 4) { console.log('绿', borders.green - current); } else { console.log('黄', borders.yellow - current); } current++; if (current > 5) { current = 0; } }, 1000); } trafficCtrl(); ``` 红 3 红 2 红 1 绿 2 绿 1 黄 1 红 3 红 2 …
FrankKai commented 3 years ago

数组去重

输入:
['1', '2', '3', 1, '2', undefined, undefined, null, null, 1, 'a','b','b'];
输出:
["1", "2", "3", 1, undefined, null, "a", "b"]
答案 ```js // 解法1:includes function removeDuplicate(arr) { const result = []; for(const item of arr){ if(!result.includes(item)) result.push(item); } return result; } // 解法2:Map function removeDuplicate(arr) { const map = new Map(); for(const item of arr){ if(!map.has(item)) map.set(item, true); } const result = [...map.keys()]; return result; } // 解法3:对撞指针 function removeDuplicate(arr) { const map = new Map(); let i = 0; let j = arr.length - 1; while(i<=j){ if(!map.has(arr[i])) map.set(arr[i], true); if(!map.has(arr[j])) map.set(arr[j], true); i++; j--; } const result = [...map.keys()]; return result; } // 解法4:filter function removeDuplicate(arr) { return arr.filter((item, i)=> arr.indexOf(item) === i) } ```
FrankKai commented 3 years ago

返回 excel 表格列名

输入:1 输出:A
输入:2 输出:B
输入:26 输出:Z
输入:27 输出:AA
输入:52 输出:AZ
答案 ```js function getExcelColumn(column) {     const obj = {};     let i = 0;     const startCode = "A".charCodeAt();     while (i < 26) {         obj[i + 1] = String.fromCharCode(startCode + i);         i++;     }     if (column <= 26) {         return obj[column]     }     const stack = [];     const left = column % 26;     const floor = Math.floor(column / 26);     if (left) {         stack.unshift(obj[left])         stack.unshift(obj[floor]);     } else {         stack.unshift('Z')         stack.unshift(obj[floor - 1]);     }     const result = stack.join("");     return result; } ``` 这是一道leetcode 简单难度的题。 题目:[leetcode 168 Excel表列名称](https://leetcode-cn.com/problems/excel-sheet-column-title/) 题解:[168 Excel表列名称](https://github.com/FrankKai/leetcode-js/blob/master/168.Excel_Sheet_Column_Title.js)
FrankKai commented 3 years ago

如何检测一个空对象

如何检测出{}这样的空对象
答案 ```js // 解法1: Object.prototype.toString.call和JSON.stringify function isObjEmpty(obj){ return Object.prototype.toString.call(obj)==="[object Object]" && JSON.stringify({}) === "{}"; } // 解法2: Object.keys() Object.values() function isObjEmpty(obj){ return Object.keys(obj).length === 0 || Object.values(obj).length === 0; } // 解法3:for...in function isObjEmpty(obj){ for(key in obj){ if(key) return false } return true; } ```
FrankKai commented 3 years ago

实现a+a+a打印'abc'

console.log(a + a + a); // 打印'abc'
答案 ```js /* console.log(a + a + a); // 打印'abc' */ /** * 解法1: Object.defineProperty() 外部变量 */ let value = "a"; Object.defineProperty(this, "a", { get() { let result = value; if (value === "a") { value = "b"; } else if (value === "b") { value = "c"; } return result; }, }); console.log(a + a + a); /** * 解法1(优化版):Object.defineProperty() 内部变量 */ Object.defineProperty(this, "a", { get() { this._v = this._v || "a"; if (this._v === "a") { this._v = "b"; return "a"; } else if (this._v === "b") { this._v = "c"; return "b"; } else { return this._v; } }, }); console.log(a + a + a); /** * 解法2: Object.prototpye.valueOf() */ let index = 0; let a = { value: "a", valueOf() { return ["a", "b", "c"][index++]; }, }; console.log(a + a + a); /** * 解法3:charCodeAt,charFromCode */ let code = "a".charCodeAt(0); let count = 0; Object.defineProperty(this, "a", { get() { let char = String.fromCharCode(code + count); count++; return char; }, }); console.log(a + a + a); // 'abc' /** * 解法3(优化版一):内部变量this._count和_code */ Object.defineProperty(this, "a", { get() { let _code = "a".charCodeAt(0); this._count = this._count || 0; let char = String.fromCharCode(_code + this._count); this._count++; return char; }, }); console.log(a + a + a); // 'abc' /** * 解法3(优化版二):内部变量this._code */ Object.defineProperty(this, "a", { get() { this._code = this._code || "a".charCodeAt(0); let char = String.fromCharCode(this._code); this._code++; return char; }, }); console.log(a + a + a); // 'abc' /* 题目扩展: 打印`a...z` a+a+a; //'abc' a+a+a+a; //'abcd' */ /** * charCodeAt,charFromCode */ let code = "a".charCodeAt(0); let count = 0; Object.defineProperty(this, "a", { get() { let char = String.fromCharCode(code + count); if (count >= 26) { return ""; } count++; return char; }, }); // 打印‘abc’ console.log(a + a + a); // 'abc' // 打印‘abcd’ let code = "a".charCodeAt(0); let count = 0; // {...定义a...} console.log(a + a + a); // 'abcd' // 打印‘abcdefghijklmnopqrstuvwxyz’ let code = "a".charCodeAt(0); let count = 0; // {...定义a...} let str = ""; for (let i = 0; i < 27; i++) { str += a; } console.log(str); // "abcdefghijklmnopqrstuvwxyz" /* 题目扩展(优化版): 打印`a...z` a+a+a; //'abc' a+a+a+a; //'abcd' */ Object.defineProperty(this, "a", { get() { this._code = this._code || "a".charCodeAt(0); let char = String.fromCharCode(this._code); if (this._code >= "a".charCodeAt(0) + 26) { return ""; } this._code++; return char; }, }); // 打印‘abc’ console.log(a + a + a); // 'abc' ```
FrankKai commented 3 years ago

实现一个Event模块

简单实现一个事件订阅机制,具有on、emit、once、off
on(event, func){ ... }
emit(event, ...args){ ... }
once(event, func){ ... }
off(event, func){ ... }

const event = new EventEmitter();
event.on('someEvent', (...args) => {
     console.log('some_event triggered', ...args);
});
event.emit('someEvent', 'abc', '123');
event.once('someEvent', (...args) => {
     console.log('some_event triggered', ...args);
});
event.off('someEvent', callbackPointer);
答案 ```js class EventEmitter { constructor() { this.map = new Map() } on(event, func) { const e = { name: event, handler: { type: 'persistent', func } } const { handlers } = this.map.get(e.name) || {} this.map.set(e.name, this.map.has(e.name) ? { handlers: [...handlers, e.handler] } : { handlers: [e.handler] }) } emit(event, ...args) { const e = { name: event } const { handlers } = this.map.get(e.name) || {} if (!handlers) return for (const handler of handlers) { handler.func(...args) } // 过滤 this.map.set(e.name, { handlers: handlers.filter((handler) => handler.type !== 'once') }) // console.log('emit', this.map) } once(event, func) { const e = { name: event, handler: { func, type: 'once' } } const { handlers } = this.map.get(e.name) || {} this.map.set(e.name, this.map.has(e.name) ? { handlers: [...handlers, e.handler] } : { handlers: [e.handler] }) // console.log('once', this.map) } off(event, func) { const e = { name: event, handler: { func } } const { handlers } = this.map.get(e.name) || {} if (!handlers) return const leftHandlers = handlers.filter((handler) => handler.func !== func) this.map.set(e.name, { handlers: leftHandlers }) // console.log('off', this.map) } } const event = new EventEmitter() const callbackPointer = (...args) => { console.log('some_event triggered', ...args) } const callbackPointer1 = (...args) => { console.log('some_event triggered 1', ...args) } event.on('someEvent', callbackPointer) event.on('someEvent', callbackPointer1) event.emit('someEvent', 'abc', '123') event.off('someEvent', callbackPointer) event.emit('someEvent', 'abc', '123') const callbackPointer2 = (...args) => { console.log('some_event triggered 2', ...args) } const callbackPointer3 = (...args) => { console.log('some_event triggered 3', ...args) } event.once('someEvent2', callbackPointer2) event.once('someEvent2', callbackPointer3) event.emit('someEvent2', 'abc', '123') event.emit('someEvent2', 'abc', '123') const callbackPointer4 = (...args) => { console.log('some_event triggered 4', ...args) } const callbackPointer5 = (...args) => { console.log('some_event triggered 5', ...args) } event.on('someEvent3', callbackPointer4) event.once('someEvent3', callbackPointer5) event.emit('someEvent3', 'abc', '123') event.emit('someEvent3', 'abc', '123') ```
FrankKai commented 3 years ago

大整数相加

请通过代码实现大整数(可能比Number.MAX_VALUE大)相加运算
var bigint1 = new BigInt('1231230');
var bigint2 = new BigInt('12323123999999999999999999999999999999999999999999999991');
console.log(bigint1.plus(bigint2))
答案 ```js function BigInt(value) { this.value = value; } BigInt.prototype.plus = function (bigint) { let aArr = this.value.split(""); let bArr = bigint.value.split(""); let stack = []; let count = 0; while (aArr.length !== 0 || bArr.length !== 0) { let aPop = aArr.pop() || 0; let bPop = bArr.pop() || 0; let stackBottom = 0; if (stack.length > count) { stackBottom = stack.shift(); } let sum = parseInt(aPop) + parseInt(bPop) + parseInt(stackBottom); if (sum < 10) { stack.unshift(sum); } else if (sum >= 10) { stack.unshift(sum - 10); stack.unshift(1); } count++; } return stack.join(""); }; ```
FrankKai commented 3 years ago

SuperPerson继承Person

写一个类Person,拥有属性age和name,拥有方法say(something)
再写一个类Superman,继承Person,拥有自己的属性power,拥有自己的方法fly(height) ES5方式
答案 ```js function Person(age, name){ this.age = age; this.name = name; } Person.prototype.say = function(something) { // ... } function Superman(age, name, power){ Person.call(this, age, name, power); this.power = power; } Superman.prototype = Object.create(Person.prototype); Superman.prototype.constructor = Superman; Superman.prototype.fly = function(height) { // ... } let superman = new Superman(25, 'GaoKai', 'strong'); // class方式 class Person { constructor(age, name){ this.age = age; this.name = name; } say(something){ // ... console.log("say"); } } class Superman extends Person{ constructor(age, name, power){ super(age, name) this.power = power; } fly(height){ // ... console.log("fly"); } } let superman = new Superman(25, 'GaoKai', 'strong'); ```
FrankKai commented 3 years ago

字符串隐藏部分内容

字符串隐藏部分内容
说明:实现一个方法,接收一个字符串和一个符号,将字符串中间四位按指定符号隐藏
1. 符号无指定时使用星号(*)
2. 接收的字符串小于或等于四位时,返回同样长度的符号串,等同于全隐藏,如 123,隐藏后是 ***
3. 字符串长度是大于四位的奇数时,如 123456789,隐藏后是 12****789,奇数多出来的一位在末尾
示例:
mask('blibaba', '#');  // b####ba
mask('05716666');   // 05****66
mask('hello');  // ****o
mask('abc', '?');  // ???
mask('哔里巴巴集团', '?'); // 哔????团
答案 ```js function mask(str, char = "*") { if(str.length<=4) return char.repeat(str.length); /* 代码实现 */ let result = ""; let i = Math.floor(str.length / 2) - 1; let j = Math.floor(str.length / 2); while(result.length!==str.length){ if(j - i <= 4){ result = char + result; result += char ; } else { result = (str[i] || "") + result; result += str[j] ; } i--; j++; } return result; } ```
FrankKai commented 3 years ago

实现一个sum(1,2,3)(4)(5)(6,7)(8)()

返回结果为这些数字的和:36。

这是一道考察求和+闭包+递归的题目。

答案 ```js function sum(){ const result = [...arguments].reduce((acc, cur)=>acc+cur) return function(){ if(arguments.length === 0)return result return sum(...[...arguments, result]); } } ```
FrankKai commented 3 years ago

实现一个sum(1,2,3)(4)(5)(6,7)(8)()升级版:如何实现加,减,乘,除呢?

sum(1,2,3)(4)(5)(6,7)(8)()
minus(1,2,3)(4)(5)(6,7)(8)()
multiple(1,2,3)(4)(5)(6,7)(8)()
divide(1,2,3)(4)(5)(6,7)(8)()

除了考察求和,闭包,递归以外,还考察了柯里化函数

sum和multiple不用关注顺序。 而minus和divide需要注意顺序,因此在return curried(...[result, ...arguments]);中将result前置了。

答案 ```js function curry(callback){ return function curried (){ const result = callback(arguments) return function(){ if(arguments.length === 0)return result return curried(...[result, ...arguments]); } } } let sum = (args) =>{ return [...args].reduce((acc, cur)=>acc+cur) } let minus = (args) =>{ return [...args].reduce((acc, cur)=>acc-cur) } let multiple = (args) =>{ return [...args].reduce((acc, cur)=>acc*cur) } let divide = (args) =>{ return [...args].reduce((acc, cur)=>acc / cur) } let currySum = curry(sum) let curryMultiple = curry(multiple) let curryDivide = curry(divide) let curryMinus = curry(minus) console.log(currySum(1,2,3)(4)(5)(6,7)(8)()) console.log(curryMultiple(1,2,3)(4)(5)(6,7)(8)()) console.log(curryDivide(1,2,3)(4)(5)(6,7)(8)()) console.log(curryMinus(1,2,3)(4)(5)(6,7)(8)()) ```
>期待和大家交流,共同进步,欢迎大家加入我创建的与前端开发密切相关的技术讨论小组: >- 微信公众号: 生活在浏览器里的我们 / excellent_developers >- Github博客: [趁你还年轻233的个人博客](https://github.com/FrankKai/FrankKai.github.io) > - SegmentFault专栏:[趁你还年轻,做个优秀的前端工程师](https://segmentfault.com/blog/chennihainianqing) >- 知乎专栏:[趁你还年轻,做个优秀的前端工程师](https://zhuanlan.zhihu.com/wyasy) ### 微信公众号: 生活在浏览器里的我们 / excellent_developers >努力成为优秀的前端工程师!