2020年冬季前端笔试题总结
Posted 趁你还年轻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020年冬季前端笔试题总结相关的知识,希望对你有一定的参考价值。
原文地址:一些特别棒的面试题[4]
最近面试了一些公司,拿了一些offer,不记录概念题目,仅记录coding类题目。
小伙伴们空闲时间可以做这些题目练练手。
- 只出现一次的数字
- 汇总区间
- 实现红绿灯效果
- 数组去重
- 返回 excel 表格列名
- 检测空对象
- 实现a+a+a打印\'abc\'
- 实现一个Event模块
- 大整数相加
- SuperPerson继承Person
- 字符串隐藏部分内容
- 实现一个sum(1,2,3)(4)(5)(6,7)(8)()
- 实现一个sum(1,2,3)(4)(5)(6,7)(8)()升级版:如何实现加,减,乘,除呢?
只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
这是一道leetcode 简单难度的题。
题目:leetcode 136 只出现一次的数字
题解:136 只出现一次的数字
/**
* @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];
};
汇总区间
给定一个乱序整形数组[0,1,7,13,15,16,2,4,5],找出其中连续出现的数字区间为如下:["0->2", "4->5", "7", "13", "15->16"]
这是一道leetcode 中等难度的题。
题目:leetcode 228 汇总区间
题解:228汇总区间(Summary Ranges)
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]));
实现红绿灯效果,使用console 输出 “红”、“绿”、“黄”示意,等待时间分别为 3s、2s、1s
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
…
数组去重
输入:
[\'1\', \'2\', \'3\', 1, \'2\', undefined, undefined, null, null, 1, \'a\',\'b\',\'b\'];
输出:
["1", "2", "3", 1, undefined, null, "a", "b"]
// 解法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)
}
写一个函数返回 excel 表格列名
输入:1 输出:A
输入:2 输出:B
输入:26 输出:Z
输入:27 输出:AA
输入:52 输出:AZ
这是一道leetcode 简单难度的题。
题目:leetcode 168 Excel表列名称
题解:168 Excel表列名称
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;
}
如何检测一个空对象
// 解法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;
}
实现a+a+a打印\'abc\'
console.log(a + a + a); // 打印\'abc\'
// 题目一
/*
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\'
实现一个Event模块
/**
* 说明:简单实现一个事件订阅机制,具有监听on和触发emit方法
* 示例:
* 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); // callbackPointer为回调指针,不能是匿名函数
*/
class EventEmitter {
constructor() {
this.listeners = [];
}
on(event, func) {
const callback = () => (listener) => listener.name === event;
const idx = this.listeners.findIndex(callback);
if (idx === -1) {
this.listeners.push({
name: event,
callbacks: [func],
});
} else {
this.listeners[idx].callbacks.push(func);
}
}
emit(event, ...args) {
if (this.listeners.length === 0) return;
const callback = () => (listener) => listener.name === event;
const idx = this.listeners.findIndex(callback);
this.listeners[idx].callbacks.forEach((cb) => {
cb(...args);
});
}
once(event, func) {
const callback = () => (listener) => listener.name === event;
let idx = this.listeners.findIndex(callback);
if (idx === -1) {
this.listeners.push({
name: event,
callbacks: [func],
});
}
}
off(event, func) {
if (this.listeners.length === 0) return;
const callback = () => (listener) => listener.name === event;
let idx = this.listeners.findIndex(callback);
if (idx !== -1) {
let callbacks = this.listeners[idx].callbacks;
for (let i = 0; i < callbacks.length; i++) {
if (callbacks[i] === func) {
callbacks.splice(i, 1);
break;
}
}
}
}
}
// let event = new EventEmitter();
// let onceCallback = (...args) => {
// console.log("once_event triggered", ...args);
// };
// let onceCallback1 = (...args) => {
// console.log("once_event 1 triggered", ...args);
// };
// // once仅监听一次
// event.once("onceEvent", onceCallback);
// event.once("onceEvent", onceCallback1);
// event.emit("onceEvent", "abc", "123");
// // off销毁指定回调
// let onCallback = (...args) => {
// console.log("on_event triggered", ...args);
// };
// let onCallback1 = (...args) => {
// console.log("on_event 1 triggered", ...args);
// };
// event.on("onEvent", onCallback);
// event.on("onEvent", onCallback1);
// event.emit("onEvent", "abc", "123");
// event.off("onEvent", onCallback);
// event.emit("onEvent", "abc", "123");
大整数相加
/**
* 请通过代码实现大整数(可能比Number.MAX_VALUE大)相加运算
* var bigint1 = new BigInt(\'1231230\');
* var bigint2 = new BigInt(\'12323123999999999999999999999999999999999999999999999991\');
* console.log(bigint1.plus(bigint2))
*/
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("");
};
SuperPerson继承Person
//写一个类Person,拥有属性age和name,拥有方法say(something)
//再写一个类Superman,继承Person,拥有自己的属性power,拥有自己的方法fly(height) ES5方式
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\');
字符串隐藏部分内容
/**
* 字符串隐藏部分内容
* 说明:实现一个方法,接收一个字符串和一个符号,将字符串中间四位按指定符号隐藏
* 1. 符号无指定时使用星号(*)
* 2. 接收的字符串小于或等于四位时,返回同样长度的符号串,等同于全隐藏,如 123,隐藏后是 ***
* 3. 字符串长度是大于四位的奇数时,如 123456789,隐藏后是 12****789,奇数多出来的一位在末尾
* 示例:
* mask(\'blibaba\', \'#\'); // b####ba
* mask(\'05716666\'); // 05****66
* mask(\'hello\'); // ****o
* mask(\'abc\', \'?\'); // ???
* mask(\'哔里巴巴集团\', \'?\'); // 哔????团
*/
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;
}
实现一个sum(1,2,3)(4)(5)(6,7)(8)()
返回结果为这些数字的和:36。
这是一道考察求和+闭包+递归的题目。
function sum(){
const result = [...arguments].reduce((acc, cur)=>acc+cur)
return function(){
if(arguments.length === 0)return result
return sum(...[...arguments, result]);
}
}
实现一个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前置了。
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的个人博客
- SegmentFault专栏:趁你还年轻,做个优秀的前端工程师
努力成为优秀前端工程师!
以上是关于2020年冬季前端笔试题总结的主要内容,如果未能解决你的问题,请参考以下文章