算法代码面试题
第 11 题:算法手写题
已知如下数组,编写一个程序将数组扁平化去并除其中重复部分数据,最终得
到一个升序且不重复的数组
var arr = [ [1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14] ] ] ], 10];
答:使用 Set 方法去重,flat(Infinity)扁平化
Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})//[1,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
第 30 题:两个数组合并成一个数组
请把两个数组 ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'] 和 ['A', 'B', 'C', 'D'],合并
为 ['A1', 'A2', 'A', 'B1', 'B2', 'B', 'C1', 'C2', 'C', 'D1', 'D2', 'D']。
function concatArr (arr1, arr2) { const arr = [...arr1];
let currIndex = 0;
for (let i = 0; i < arr2.length; i++) {
const RE = new RegExp(arr2[i])
while(currIndex < arr.length) {
++currIndex
if (!RE.test(arr[currIndex])) {
arr.splice(currIndex, 0, a2[i])
break;
}
}
}
return arr } var a1 = ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1',
'D2']
var a2 = ['A', 'B', 'C', 'D'] const arr = concatArr(a1, a2)
console.log(a1)
// ['A1', 'A2', 'B1', 'B2', 'C1', 'C2', 'D1', 'D2'] console.log(a2)
// ['A', 'B', 'C', 'D'] console.log(arr)
// ['A1', 'A2', 'A', B1', 'B2', 'B', C1', 'C2', 'C', D1', 'D2', 'D']
第 31 题:改造下面的代码,使之输出 0 - 9,写出你能想到的
所有解法。
for (var i = 0;
i< 10; i++){
setTimeout(() => {
console.log(i);
}, 1000)}
答:
// 解法一:for (let i = 0;
i< 10;
i++){
setTimeout(() => {
console.log(i);
}, 1000)}
// 解法二:for (var i = 0;
i< 10; i++){ ((i) => {
setTimeout(() => {
console.log(i);
}, 1000) })(i)}
第 33 题:下面的代码打印什么内容,为什么?
var b = 10;
(function b(){
b = 20;
console.log(b);
})();
答:
ƒ b(){
b = 20;
console.log(b);
}
首先函数声明比变量要高,其次 b = 20 没有 var 获取其他,说明是 window 最
外层定义的变量。
js 作用域中,先找最近的 那就是 b fn ,直接打印了,如果 b = 20 有 var 那就
是打印 20
第 34 题:简单改造下面的代码,使之分别打印 10 和 20。
var b = 10;
(function b(){
b = 20;
console.log(b);
})();
答:
var b = 10;
(function (){
b = 20;
console.log(b);
// 20})();
var b = 10;
(function (){
console.log(b);
// 10 b = 20;
})();
第 36 题:使用迭代的方式实现 flatten 函数。
var arr=[1,2,3,[4,5],[6,[7,[8]]]]/** * 使用递归的方式处理 * wrap 内保
存结果 ret * 返回一个递归函数 * * @returns */function wrap(){
var ret=[];
return function flat(a){
for(var item of
a){ if(item.constructor===Array){
ret.concat(flat(item))
}else{
ret.push(item)
}
}
return ret
}}console.log(wrap()(arr));
第 38 题:(京东)下面代码中 a 在什么情况下会打印 1?
var a = ?;
if(a == 1 && a == 2 && a == 3){
console.log(1);
}
答:
var a = {
i: 1,
toString() {
return a.i++;
}}if( a == 1 && a == 2 && a == 3 ) {
console.log(1);
}let a = [1,2,3];
a.toString = a.shift;if( a == 1 && a == 2 && a == 3 ) {
console.log(1);}
第 41 题:下面代码输出什么
var a = 10;(function () {
console.log(a)
a = 5
console.log(window.a)
var a = 20;
console.log(a)})()
分别为 undefined 10 20,原因是作用域问题,在内部声名 var a = 20;相当于
先声明 var a;然后再执行赋值操作,这是在IIFE内形成的独立作用域,如果
把 var a=20 注释掉,那么 a 只有在外部有声明,显示的就是外部的A变量的值
了。结果A会是 10 5 5
第 42 题:实现一个 sleep 函数
比如 sleep(1000) 意味着等待 1000 毫秒,可从 Promise、Generator、Async/Await
等角度实现
const sleep = (time) => {
return new Promise(resolve => setTimeout(resolve,
time))}sleep(1000).then(() => {
// 这里写你的骚操作})
第 43 题:使用 sort() 对数组 [3, 15, 8, 29, 102, 22] 进
行排序,输出结果
输出:[102, 15, 22, 29, 3, 8]
解析:根据 MDN 上对 Array.sort()的解释,默认的排序方法会将数组元素转换
为字符串,然后比较字符串中字符的 UTF-16 编码顺序来进行排序。所以'102' 会
排在 '15' 前面。
第 46 题:输出以下代码执行的结果并解释为什么
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push':
Array.prototype.push}obj.push(1)obj.push(2)console.log(obj)
结果:[,,1,2], length 为 4
伪数组(ArrayLike)
第 53 题:输出以下代码的执行结果并解释为什么
var a = {n: 1};
var b = a;a.x = a = {n: 2};
console.log(a.x)
console.log(b.x)
结果:undefined{n:2}
首先,a 和 b 同时引用了{n:2}对象,接着执行到 a.x = a = {n:2}语句,尽管赋值
是从右到左的没错,但是.的优先级比=要高,所以这里首先执行 a.x,相当于为
a(或者 b)所指向的{n:1}对象新增了一个属性 x,即此时对象将变为
{n:1;x:undefined}。之后按正常情况,从右到左进行赋值,此时执行 a ={n:2}的时
候,a 的引用改变,指向了新对象{n:2},而 b 依然指向的是旧对象。之后执行
a.x = {n:2}的时候,并不会重新解析一遍 a,而是沿用最初解析 a.x 时候的 a,
也即旧对象,故此时旧对象的 x 的值为{n:2},旧对象为 {n:1;x:{n:2}},它被 b
引用着。后面输出 a.x 的时候,又要解析 a 了,此时的 a 是指向新对象的 a,而
这个新对象是没有 x 属性的,故访问时输出 undefined;而访问 b.x 的时候,将
输出旧对象的 x 的值,即{n:2}。
第 54 题:冒泡排序如何实现,时间复杂度是多少, 还可以如
何改进?
冒泡算法的原理:
升序冒泡: 两次循环,相邻元素两两比较,如果前面的大于后面的就交换位置
降序冒泡: 两次循环,相邻元素两两比较,如果前面的小于后面的就交换位置
js 实现:
// 升序冒泡 function maopao(arr){
const array = [...arr] for(let i = 0, len = array.length; i < len -
1; i++){
for(let j = i + 1; j < len; j++) {
if (array[i] > array[j]) {
let temp = array[i]
array[i] = array[j]
array[j] = temp
}
}
}
return array
}
看起来没问题,不过一般生产环境都不用这个,原因是效率低下,冒泡排序在
平均和最坏情况下的时间复杂度都是 O(n^2),最好情况下都是 O(n),空间复
杂度是 O(1)。因为就算你给一个已经排好序的数组,如[1,2,3,4,5,6] 它也会走
一遍流程,白白浪费资源。所以有没有什么好的解决方法呢?
答案是肯定有的:加个标识,如果已经排好序了就直接跳出循环。
优化版:
function maopao(arr){
const array = [...arr]
let isOk = true for(let i = 0, len = array.length;
i < len - 1; i++){
for(let j = i + 1; j < len; j++) {
if (array[i] > array[j]) {
let temp = array[i]
array[i] = array[j]
array[j] = temp
isOk = false
}
}
if(isOk){
Break
}
}
return array}
测试: 数组:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
第 55 题:某公司 1 到 12 月份的销售额存在一个对象里面
如下:{1:222, 2:123, 5:888},请把数据处理为如下结构:[222, 123, null, null, 888, null, null, null, null, null, null, null]。
let obj = {1:222, 2:123, 5:888};
const result = Array.from({ length: 12 }).map((_, index) => obj[index +
1] || null);
console.log(result)
第 56 题:要求设计 LazyMan 类,实现以下功能。
LazyMan('Tony');
// Hi I am Tony
LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了 10 秒...
// I am eating
lunchLazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch// 等待了 10 秒...
// I am eating
dinerLazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(1
0).eat('junk food');
// Hi I am Tony// 等待了 5 秒...
// I am eating lunch
// I am eating dinner
// 等待了 10 秒...
// I am eating junk food
答:
class LazyManClass {
constructor(name) {
this.name = name
this.queue = []
console.log(Hi I am ${name})
setTimeout(() => {
this.next()
},0)
}
sleepFirst(time) {
const fn = () => {
setTimeout(() => {
console.log(等待了${time}秒...)
this.next()
}, time)
}
this.queue.unshift(fn)
return this
}
sleep(time) {
const fn = () => {
setTimeout(() => {
console.log(等待了${time}秒...)
this.next()
},time)
}
this.queue.push(fn)
return this
}
eat(food) {
const fn = () => {
console.log(I am eating ${food})
this.next()
}
this.queue.push(fn)
return this
}
next() {
const fn = this.queue.shift()
fn && fn() }}function LazyMan(name) {
return new LazyManClass(name)}
第 59 题:给定两个数组,写一个方法来计算它们的交集。
例如:给定 nums1 = [1, 2, 2, 1],nums2 = [2, 2],返回 [2, 2]。
var nums1 = [1, 2, 2, 1], nums2 = [2, 2, 3, 4];
// 1.
// 有个问题,
[NaN].indexOf(NaN) === -1var newArr1 = nums1.filter(function(item) {
return nums2.indexOf(item) > -1;
});
console.log(newArr1);
// 2.
var newArr2 = nums1.filter((item) => {
return nums2.includes(item);
});
console.log(newArr2);
第 67 题:数组编程题
随机生成一个长度为 10 的整数类型的数组,例如 [2, 10, 3, 4, 5, 11, 10, 11, 20],将其排列成一个新数组,要求新数组形式如下,例如 [[2, 3, 4, 5], [10, 11], [20]]。
function formArray(arr: any[]) {
const sortedArr = Array.from(new Set(arr)).sort((a, b) => a - b);
const map = new Map();
sortedArr.forEach((v) => {
const key = Math.floor(v / 10);
const group = map.get(key) || [];
group.push(v);
map.set(key, group);
}); return [...map.values()];}// 求连续的版本 function
formArray1(arr: any[]) {
const sortedArr = Array.from(new Set(arr)).sort((a, b) => a - b);
return sortedArr.reduce((acc, cur) => {
const lastArr = acc.slice().pop() || [];
const lastVal = lastArr.slice().pop();
if (lastVal!=null && cur-lastVal === 1)
{
lastArr.push(cur);
} else {
acc.push([cur]);
}
return acc;
}, []);}function genNumArray(num: number, base = 100) {
return Array.from({length: num}, () =>
Math.floor(Math.random()*base));
}const arr = genNumArray(10, 20);
//[2, 10, 3, 4, 5, 11, 10, 11, 20];
const res = formArray(arr);console.log(res ${JSON.stringify(res)});
第 71 题: 实现一个字符串匹配算法,从长度为 n 的字符串 S
中,查找是否存在字符串 T,T 的长度是 m,若存在返回所在位
置。
const find = (S, T) => {
if (S.length < T.length) return -1
for (let i = 0; i < S.length; i++) {
if (S.slice(i, i + T.length) === T) return i
}
return -1
第 77 题:算法题「旋转数组」
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: [1, 2, 3, 4, 5, 6, 7] 和 k = 3 输出: [5, 6, 7, 1, 2, 3, 4] 解释: 向右旋转 1 步:
[7, 1, 2, 3, 4, 5, 6] 向右旋转 2 步: [6, 7, 1, 2, 3, 4, 5] 向右旋转 3 步: [5, 6, 7, 1, 2, 3, 4]
示例 2:
输入: [-1, -100, 3, 99] 和 k = 2 输出: [3, 99, -1, -100] 解释: 向右旋转 1 步: [99, -1, -100, 3] 向右旋转 2 步: [3, 99, -1, -100]
答:
function rotate(arr, k) {
const len = arr.length const step = k % len return
arr.slice(-step).concat(arr.slice(0, len - step))}// rotate([1, 2, 3, 4,
5, 6], 7) => [6, 1, 2, 3, 4, 5]
第 81 题:打印出 1 - 10000 之间的所有对称数
例如:121、1331 等
[...Array(10000).keys()].filter((x) => {
return x.toString().length > 1 && x ===
Number(x.toString().split('').reverse().join(''))
})
第 82 题:周一算法题之「移动零」
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非
零元素的相对顺序。
示例:
输入: [0,1,0,3,12] 输出: [1,3,12,0,0]
复制代码说明: 必须在原数组上操作,不能拷贝额外的数组。 尽量减少操作次
数
答:
function zeroMove(array) {
let len = array.length;
let j = 0;
for(let
i=0;i<len-j;i++){
if(array[i]===0){
array.push(0);
array.splice(i,1);
i --;
j ++;
}
}
return array;
}
第 84 题:请实现一个 add 函数,满足以下功能。
add(1);
// 1add(1)(2);
// 3add(1)(2)(3);
// 6add(1)(2, 3);
// 6add(1, 2)(3);
// 6add(1, 2, 3);
// 6
答:
实现 1:
function currying(fn, length) {
length = length || fn.length; // 注释 1
return function (...args) { // 注释 2 return
args.length >= length // 注释 3
? fn.apply(this, args) // 注释 4
: currying(fn.bind(this, ...args), length - args.length) // 注释
5 }}
实现 2:
const currying = fn =>
judge = (...args) =>
args.length >= fn.length
? fn(...args)
: (...arg) => judge(...args, ...arg)
其中注释部分
注释 1:第一次调用获取函数 fn 参数的长度,后续调用获取 fn 剩余参数的
长度
注释 2:currying 包裹之后返回一个新函数,接收参数为 ...args
注释 3:新函数接收的参数长度是否大于等于 fn 剩余参数需要接收的长度
注释 4:满足要求,执行 fn 函数,传入新函数的参数
注释 5:不满足要求,递归 currying 函数,新的 fn 为 bind 返回的新函数(bind
绑定了 ...args 参数,未执行),新的 length 为 fn 剩余参数的长度
第 86 题:周一算法题之「两数之和」
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
示例:
给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返
回 [0, 1]
答:
function anwser (arr, target) {
let map = {} for (let i = 0; i < arr.length; i++) {
map[arr[i]] = i }
for (let i = 0; i < arr.length; i++) {
var d = target - arr[i]
if (map[d]) {
return [i, map[d]]
}
}
return new Error('404 not found')}
第 87 题:在输入框中如何判断输入的是一个正确的网址。
function isUrl(url) {
const a = document.createElement("a");
a.href = url;
return (
[
/^(http|https)😒/.test(a.protocol),
a.host,
a.pathname !== url,
a.pathname !== /${url}
].find(x => !x) === undefined
);
}
第 88 题:实现 convert 方法,把原始 list 转换成树形结构,
要求尽可能降低时间复杂度
以下数据结构中,id 代表部门编号,name 是部门名称,parentId 是父部门编
号,为 0 代表一级部门,现在要求实现一个 convert 方法,把原始 list 转换
成树形结构,parentId 为多少就挂载在该 id 的属性 children 数组下,结构如
下:
// 原始 list 如下 let list =[
{id:1,name:'部门 A',parentId:0},
{id:2,name:'部门 B',parentId:0},
{id:3,name:'部门 C',parentId:1},
{id:4,name:'部门 D',parentId:1},
{id:5,name:'部门 E',parentId:2},
{id:6,name:'部门 F',parentId:3},
{id:7,name:'部门 G',parentId:2},
{id:8,name:'部门 H',parentId:4}];
const result = convert(list, ...);// 转换后的结果如下 let result =
[
{
id: 1,
name: '部门 A',
parentId: 0,
children: [
{
id: 3,
name: '部门 C',
parentId: 1,
children: [
{
id: 6,
name: '部门 F',
parentId: 3
}, {
id: 16,
name: '部门 L',
parentId: 3
}
]
},
{
id: 4,
name: '部门 D',
parentId: 1,
children: [
{
id: 8,
name: '部门 H',
parentId: 4
}
]
}
]
}, ···];
答:
function convert(list) {
const res = []
const map = list.reduce((res, v) => (res[v.id] = v, res), {})
for (const item of list) {
if (item.parentId === 0) {
res.push(item)
Continue
}
if (item.parentId in map) {
const parent = map[item.parentId]
parent.children = parent.children || []
parent.children.push(item)
}
}
return res}
第 92 题:已知数据格式,实现一个函数 fn 找出链条中所有的
父级 idconst value = '112'
const fn = (value) => {...}fn(value) // 输出 [1, 11, 112]
答:const data = [
{
id: "1",
name: "test1",
children: [
{
id: "11",
name: "test11",
children: [
{
id: "111",
name: "test111"
},
{
id: "112",
name: "test112"
}
]
},
{
id: "12",
name: "test12",
children: [
{
id: "121",
name: "test121"
},
{
id: "122",
name:
"test122"
}
]
}
]
}
];
const find = value => {
let result = [];
let findArr = data;
let skey = "";
for (let i = 0, l = value.length; i < l; i++) {
skey += value[i];
let item = findArr.find(item => {
return item.id == skey;
});
if (!item) {
return [];
}
result.push(item.id);
if (item.children) {
findArr = item.children;
} else {
if (i < l - 1) return [];
return result;
}
}
};
//调用看结果
function testFun() {
console.log("1,11,111:", find("111"));
console.log("1,11,112:", find("112"));
console.log("1,12,121:", find("121"));
console.log("1,12,122:", find("122"));
console.log("[]:", find("113"));
console.log("[]:", find("1114"));
}
第 93 题:给定两个大小为 m 和 n 的有序数组 nums1 和
nums2。请找出这两个有序数组的中位数。要求算法的时间复杂
度为 O(log(m+n))。
示例 1:
nums1 = [1, 3] nums2 = [2]
中位数是 2.0
示例 2:
nums1 = [1, 2] nums2 = [3, 4]
中位数是(2 + 3) / 2 = 2.5
答:
const findMedianSortedArrays = function(
nums1: number[],
nums2: number[]
) {
const lenN1 = nums1.length;
const lenN2 = nums2.length;
const median = Math.ceil((lenN1 + lenN2 + 1) / 2);
const isOddLen = (lenN1 + lenN2) % 2 === 0;
const result = new Array
let i = 0; // pointer for nums1
let j = 0; // pointer for nums2
for (let k = 0; k < median; k++) {
if (i < lenN1 && j < lenN2) {
// tslint:disable-next-line:prefer-conditional-expression
if (nums1[i] < nums2[j]) {
result[i + j] = nums1[i++];
} else {
result[i + j] = nums2[j++];
}
} else if (i < lenN1) {
result[i + j] = nums1[i++];
} else if (j < lenN2) {
result[i + j] = nums2[j++];
}
}
if (isOddLen) {
return (result[median - 1] + result[median - 2]) / 2;
} else {
return result[median - 1];
}
};
第 98 题:写出如下代码的打印结果
function changeObjProperty(o) {
o.siteUrl = "http://www.baidu.com"
o = new Object()
o.siteUrl = "http://www.google.com"
}
let webSite = new Object();
changeObjProperty(webSite);
console.log(webSite.siteUrl);
答:
webSite 属于复合数据类型,函数参数中以地址传递,修改值会影响到原始值,
但如果将其完全替换成另一个值,则原来的值不会受到影响
第 99 题:编程算法题
用 JavaScript 写一个函数,输入 int 型,返回整数逆序后的字符串。如:输入
整型 1234,返回字符串“4321”。要求必须使用递归函数调用,不能用全局变量,
输入函数必须只有一个参数传入,必须返回字符串。
function fun(num) {
let num1 = num / 10;
let num2 = num % 10;
if (num1 < 1) {
return num;
} else {
num1 = Math.floor(num1);
return ${num2}${fun(num1)};
}
}
var a = fun(12345);
console.log(a);
console.log(typeof a);
第 100 题:请写出如下代码的打印结果
function Foo() {
Foo.a = function() {
console.log(1);
};
this.a = function() {
console.log(2);
};
}
Foo.prototype.a = function() {
console.log(3);
};
Foo.a = function() {
console.log(4);
};
Foo.a();
let obj = new Foo();
obj.a();
Foo.a();
答:
4 2 1

浙公网安备 33010602011771号