手写算法: 多数元素
解法一:排序
排序数组,如果一个元素出现的频率大于 n / 2, 那么在数组中nums.length / 2的位置就是这个数
// 先排序,再找到中间这个数
var majorityElement = function(nums) {
nums.sort((a, b) => a - b);
return nums[Math.floor(nums.length / 2)];
};
解法二:哈希表
循环数组,用哈希表存储数字和对应的个数。当数字出现个数大于n / 2时,返回这个数。
var majorityElement = function(nums) {
let hash = {};
for (const num of nums) {
hash[num] = (hash[num] || 0) + 1;
if (hash[num] > nums.length >> 1) return num;
}
};
手写题:
反转二叉树
/**
* @param {Node} node
* @returns {Node}
*/
function invert(node) {
if (!node) return null;
[node.left, node.right] = [invert(node.right), invert(node.left)];
return node;
}
未排序数列的交集
传进来的两个数组,是未排序的,而且数组中也可能存在重复的数字。所以输出结果的时候,要注意是否是两个数组共同拥有的元素
解法一:都是 api 大法
利用Set()的特性去重,再筛选
/**
* @param {any[]} arr1
* @param {any[]} arr2
* @returns {any[]}
*/
function getIntersection(arr1, arr2) {
const a = new Set(arr1);
const b = new Set(arr2);
return [...a].filter(item => b.has(item));
}
function getIntersection(arr1, arr2) {
const arr = arr1.filter(item => arr2.includes(item));
return [...new Set(arr)];
}
function getIntersection(arr, arr2) {
const arr = [...new Set(arr1), ...new Set(arr2)];
let map = new Map();
let result = [];
for (const num of arr) {
map.set(num, (map.get(num) || 0) + 1);
}
for (const [key, value] of map.entries()) {
if (value > 1) {
result.push(key);
}
}
return result;
}
解法二: 遍历筛选
先排序,所以相同元素都会在一块连续的内存中
遍历的时候,如果当前元素与上一个元素相等时,就跳过不处理,继续往后走。因为同一个歌元素统计一次即可。
function getIntersection(arr1, arr2) {
arr1.sort((a, b) => a - b);
arr2.sort((a, b) => a - b);
let n = (m = 0);
let res = [],
num;
while (n < arr1.length && m < arr2.length) {
if (arr1[n] === arr2[m]) {
num = arr1[n];
res.push(num);
while (n < arr1.length && arr1[n] === num) n++;
while (m < arr2.length && arr2[m] === num) m++;
} else if (arr1[n] < arr2[m]) {
n++;
} else {
m++;
}
}
return res;
}
JS 简答题
Function name
var foo = function bar() {
return 'BFE';
};
console.log(foo());
console.log(bar());
名称 bar 是在函数表达式中使用的, 所以不会在外部声明。所以会报ReferenceError: bar is not defined
Addition vs Unary Plus
console.log(1 + 2)
console.log(1 + + 2)
console.log(1 + + + 2)
console.log(1 + '2')
console.log(1 + + '2')
console.log('1' + 2)
console.log('1' + + 2)
console.log(1 + true)
console.log(1 + + true)
console.log('1' + true)
console.log('1' + + true)
console.log(1 + null)
console.log(1 + + null)
console.log('1' + null)
console.log('1' + + null)
console.log(1 + undefined)
console.log(1 + + undefined)
console.log('1' + undefined)
console.log('1' + + undefined)
console.log('1' + + + undefined)
补习一下:一元运算符、加减运算符
+ 加法运算符适用于数字和字符串(拼接),如果任何操作数不是数字,则使用+将所有操作数转换成字符串并连接起来。
一元加号运算符(+)在操作数之前,如果尚未将其转换成数字,则尝试先转换成数字。【所以它始终会转换成数字】
✅ 一元运算符的优先级高于加法运算符
看一下 ECMAScript 大宝典:
总结规则
A + B:
prim1 = ToPrimitive(A)
prim2 = ToPrimitive(B)
如果 prim1 或 prim2 中任何一个是字符串,则返回 ToString(prim1) + ToString(prim2)
否则 ToNumber(prim1) + ToNumber(prim2)
看几个例子,实操一下
Eg1: 1 + undefined
prim1 = ToPrimitive(1) = 1;
prim2 = ToPrimitive(undefined) = undefined;
// 它们都不是字符串,转换成数字
ToNumber(1) + ToNumber(undefined)
==> 1 + NaN
==> NaN
Eg2: '1' + undefined
prim1 = ToPrimitive('1') = '1'
prim2 = ToPrimitive(undefined) = undefined;
// 其中有一个是字符串,所以转换成字符串拼接
ToString('1') + ToString(undefined)
==> '1' + 'NaN'
==> '1NaN'
Eg3: '1' + +undefined
一元运算: +undefined ==> NaN
prim1 = ToPrimitive('1') = '1'
prim2 = ToPrimitive(NaN) = NaN;
// 其中有一个是字符串,所以转换成字符串拼接
ToString('1') + ToString(NaN)
==> '1' + 'NaN'
==> '1NaN'
Eg4: '1' + +null
一元运算: +null ==> 0
prim1 = ToPrimitive('1') = '1'
prim2 = ToPrimitive(0) = 0;
// 其中有一个是字符串,所以转换成字符串拼接
ToString('1') + ToString(0)
==> '1' + '0'
==> '10'
再看看平时经常用到的
+1; // 1
+'1'; // 1
+true; // 1
+null; // 0
+undefined; // NaN
+NaN; // NaN