1. 箭头函数
箭头函数
x => x * x
相当于:
function (x) {
return x * x;
}
2. 数组排序:sort()方法
1)默认地,sort() 函数根据字符串Unicode码。
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort(); // 对 fruits 中的元素进行排序
该函数很适合字符串(“Apple” 会排在 “Banana” 之前)。
2)比较函数的目的是定义另一种排序顺序。
比较函数应该返回一个负,零或正值,这取决于参数。
升序排序:
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){
return a - b}); //可以写成points.sort((a,b) = > a-b);
降序排序:
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){
return b - a});
随机顺序排序:
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){
return 0.5 - Math.random()});
3. 数组去重
利用ES6的Set数据结构,Set类似数组,但里面的元素不重复
const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
// 用...(展开操作符)操作符将Set转换为Array
console.log([...new Set(numbers)])
// 或者:Array.from(new Set(numbers));也可以实现将set对象转换成数组
// [2, 3, 4, 5, 6, 7, 32]
4. 数组
JavaScript的数组是一个拥有堆栈和队列自身优点的global对象。也就是说JavaScript数组可以表现的像栈(LIFO)和队列(FIFO)一样操作。
常用方法:
splice()
、slice()
、push()
、unshift()
、pop()
、shift()
、join()
、reverse()
、sort()
、concat()
、split()
push():向数组末尾添加一个或者多个元素,并返回新的长度
pop():删除数组的最后一个元素,把数组的长度减1,并且返回它被删除元素的值,如果数组变为空,则该方法不改变数组,返回undefine值
unshift():是向数组的开头添加一个或多个元素,并且返回新的长度
shift():用于把数组的第一个元素从其中删除,并返回被删除的值。如果数组是空的,shift()方法将不进行任何操作,返回undefined的值
join() :数组转字符串,方法只接收一个参数:即默认为逗号分隔符
reverse() (反转数组):方法用于颠倒数组中元素的顺序
concat() :用于连接两个或多个数组
slice():arr.slice(start , end); 数组截取,返回一个新的数组,包含从 start 到 end (不包括该元素)的 arr 中的元素
indexOf() :返回某个指定的字符串值在字符串中首次出现的位置
split() :用于把一个字符串分割成字符串数组
参考博客:js数组常用方法
类比:字符串String方法
obj.charAt(index)
返回index位置的字符
obj.charCodeAt()
返回index位置的字符编码
obj.indexOf("str")
顺序搜索str,返回其位置,未找到返回-1
obj.lastIndexOf("str")
倒序搜索str,返回其位置,未找到返回-1
slice(start,end):同数组
substring(start,end):同上,区别在于参数为负数时自动转换为0,并且较小的数为起始位
substr(start,len):同上,len 表示截取的长度
补充:Date对象的方法
getDate() 获得以数值计(1-31)的日
getDay() 或者以数值计(0-6)的周
getFullYear() 获得四位的年(yyyy)
getHours() 获得时(0-23)
getMilliseconds() 获得毫秒(0-999)
getMinutes() 获得分钟(0-59)
getMonth() 获得月(0-11)
getSeconds() 获得秒(0-59)
getTime() 获得时间(1970 年 1 月 1 日以来的毫秒)
5. 输出空格
- 使用输出html标签 来解决
document.write(" "+"1"+" "+"23");
结果: 1 23
- 使用CSS样式来解决
document.write("<span style='white-space:pre;'>"+" 1 2 3 "+"</span>");
结果: 1 2 3
在输出时添加“white-space:pre;”样式属性。这个样式表示"空白会被浏览器保留"
6. confirm 消息对话框、prompt 消息对话框、打开新窗口(window.open)、关闭窗口(window.close)
还包括一些DOM的基本操作,比如:
document.getElementById(“id”)
,
改变元素内容Object.innerHTML
,
修改HTML样式(比如background、color等,还包括显示或隐藏效果display)Object.style.fontsize=20
,
修改类名object.className = classname
。
7. 二叉搜索树的中序遍历
function inOrder(root){
// 中序遍历得到有序数组(递增)
if(!root){
return false; // 此处判断root是否为空必须要加上
}
inOrder(root.left);
// 中序遍历的关键点,进而pushpush每一个元素得到递增数组
numbers.push(root.val); //push()函数用于向当前数组的添加一个或多个元素,并返回新的数组长度。
inOrder(root.right);
}
inOrder(root);
8. 展开运算符(…)
可以合并多个数组。
类数组对象变成数组。
9. 广度优先搜索BFS
var levelOrder = function(root) {
if(!root) return [];
let queue = [root]; // 队列,记录当前层的结点
let result = [];
let step = 0;
// 广度优先搜索(Breadth First Search)(其实是二叉树的层次遍历),又叫宽度优先搜索或横向优先搜索,是从根结点开始沿着树的宽度搜索遍历
while(queue.length){
result[step] = [];
let len = queue.length;
while(len){
// shift()用于把数组的第一个元素从其中删除,并返回被删除的值。如果数组是空的,shift()方法将不进行任何操作,返回undefined的值
let first = queue.shift();
result[step].push(first.val);
// console.log(first)
if(first.left) queue.push(first.left);
if(first.right) queue.push(first.right);
len--;
}
step++;
// console.log(queue)
}
return result;
};
10. 深度优先搜索DFS
var levelOrder = function(root) {
if(!root) return [];
let result = []; // 存放结果
// 深度优先搜索(Depth First Search)(其实是二叉树的先序遍历)是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
dfs(root,0,result);
return result;
};
function dfs(root,step,result){
if(root){
if(!result[step]) result[step] = []; // 此判断必须这样写,result[step] ==== null 无效
result[step].push(root.val); // 用来记录每一层的节点
dfs(root.left, step + 1, result);
dfs(root.right, step + 1, result);
}
}
11. 双指针
// 标签:数组遍历
// 首先对数组进行排序,排序后固定一个数 nums[i],再使用左右指针指向 nums[i]后面的两端,数字分别为 nums[L] 和 nums[R],计算三个数的和 sum 判断是否满足为0,满足则添加进结果集
// 如果 nums[i]大于 0,则三数之和必然无法等于 0,结束循环
// 如果 nums[i] == nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过
// 当 sum == 0 时,nums[L] == nums[L+1] 则会导致结果重复,应该跳过,L++
// 当 sum == 0 时,nums[R] == nums[R−1] 则会导致结果重复,应该跳过,R−−
// 时间复杂度:O(n2),n 为数组长度
var threeSum = function(nums) {
let ans = [];
nums.sort((a,b) => a-b); // 升序排序,箭头函数
for(let i = 0;i<nums.length-2;i++){
if(nums[i] > 0) break; // 如果 nums[i]大于 0,则三数之和必然无法等于 0,结束循环
if(nums[i] == nums[i-1] && i>0){
// 如果 nums[i] == nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过
continue;
}
// 双指针
let start = i+1;
let end = nums.length-1;
while(start < end){
let sum = nums[start] + nums[end] + nums[i];
if(sum == 0){
if(start-1>i && nums[start] == nums[start-1]){
// 或者:nums[start] == nums[start+1]
start++;
continue;
}
if(end+1<nums.length-1 && nums[end] == nums[end+1]){
// nums[end] == nums[end−1]
end--;
continue;
}
// while (nums[start] == nums[start+1]) start++; // 去重
// while (nums[end] == nums[end-1]) end--; // 去重
ans.push([nums[i],nums[start],nums[end]]); // JavaScript的数组是一个拥有堆栈和队列自身优点的global对象。
start++;
end--;
}
else if(sum < 0) start++;
else end--;
}
}
return ans;
};
12. 哈希表
// 哈希表
// Map是一组键值对的结构,具有极快的查找速度
var getIntersectionNode = function(headA, headB) {
let map = new Map();
let node = headA;
while(node){
map.set(node,true); // 添加新的键值对,并对每一个node节点赋真值true
node = node.next;
}
node = headB;
while(node){
if(map.has(node)) return node; // 判断是否存在键“node”
node = node.next;
}
return null;
};
//哈希表是基于键值对的一种数据存储结构,key值不可以重复,value可以重复,后面添加的重复的key值的时候,会把之前key值对应的value给覆盖掉,JavaScript中的对象具有天然的哈希特性。
//使用一层循环,每遍历到一个元素就计算该元素与 target 之间的差值 dif,然后以 dif 为下标到数组temp中寻找,如果 temp[dif] 有值(即不是undefined),则返回两个元素在数组 nums 的下标,如果没有找到,则将当前元素存入数组temp 中。
//时间复杂度:O(n)。
//var声明的变量只能是全局的或者是整个函数块的;let则允许声明一个作用域被限制在块级中的变量、语句或者表达式
var twoSum = function(nums, target) {
let temp = []
for (let i = 0; i < nums.length; i++) {
let dif = target-nums[i]
if (temp[dif] !== undefined) {
return [temp[dif], i]
}
temp[nums[i]] = i;//记录数组nums对应每一个元素的下标
}
};
13. 循环遍历数组
1)for循环
var array = [1,2,3,4,5,6,7];
for (var i = 0; i < array.length; i) {
console.log(i,array[i]);
}
2)for in
for(let index in array) {
console.log(index,array[index]);
};
3)for of
for(let v of array) {
console.log(v);
};
4)forEach
array.forEach(v=>{
console.log(v);
});
【补充】
for in总是得到对像的key或数组,字符串的下标,而for of和forEach一样,是直接得到值。
14. N叉树的前序遍历
// 二N叉树的前序遍历就是先遍历根节点,然后依次递归遍历每个子树。
var preorder = function(root) {
if(!root) return [];
let result = [];
function order(root){
if(root){
result.push(root.val);
// forEach循环遍历数组,得到的是值
root.children.forEach(child => {
order(child);
})
}
}
order(root);
return result;
};
15. 二叉树的三序遍历(迭代法)
- 前序遍历:根-左-右
- 中序遍历:左-根-右
- 后续遍历:左-右-根
栈:先进后出
前序遍历:
var preorderTraversal = function(root) {
let res = [];
if(!root){
return res;
}
// 对任意一个节点附加一个标识:
// true:表示当前节点是三序遍历中相应顺序的根节点,碰到需要加入结果集
// false:表示此节点属于三序遍历中的左、右子树的操作,需要压入栈中
let stack = [[root,false]];
while(stack.length > 0){
let node = stack.pop();
let curr = node[0];
let isTrue = node[1];
if(isTrue){
res.push(curr.val);
}else{
if(curr.right){
stack.push([curr.right,false]);
}
if(curr.left){
stack.push([curr.left,false]);
}
stack.push([curr,true]);
}
}
return res;
};
参考:二叉树的三序遍历
16. Map和Set集合
Map:
Map是一组键值对的结构,具有极快的查找速度。
初始化Map需要一个二维数组,或者直接初始化一个空Map。Map具有以下方法:
var m = new Map(); // 空Map
2 m.set('Adam', 67); // 添加新的key-value
3 m.set('Bob', 59);
4 m.has('Adam'); // 是否存在key 'Adam': true
5 m.get('Adam'); // 67
6 m.delete('Adam'); // 删除key 'Adam'
7 m.get('Adam'); // undefined
举例:
1 var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
2 m.get('Michael'); // 95
Set:
Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
17. 回溯算法
经典问题:八皇后问题
/**
* @param {string} s
* @return {string[]}
*/
var permutation = function(s) {
let res = new Set();
let visit = [];
// 深度优先搜索
function dfs(path){
// console.log("已调用dfs")
if(path.length === s.length) res.add(path);
for(let i = 0; i < s.length; i++){
if(visit[i]) continue;
visit[i] = true;
dfs(path + s[i]);
visit[i] = false;
}
}
dfs('');
return [...res];
};
18. 滑动窗口算法
/**
* @param {number} target
* @return {number[][]}
*/
// 滑动窗口算法
// 发现本题中所有输出结果都是按着顺序从小到大排列的
var findContinuousSequence = function(target) {
let index = target%2 === 0 ? target/2 : parseInt(target/2) + 1;
let res = [];
let temp = [];
let sum = 0;
for(let i = 1; i <= index; i++){
temp.push(i);
sum += i;
// 当sum > target时,删除temp中第一个元素,相应的sum应减掉第一个数组元素,直到sum <= target再执行下一步代码
while (sum > target){
// let _shift = temp.shift();
sum -= temp.shift(); // shift():用于把数组的第一个元素从其中删除,并返回被删除的值
}
if(sum === target && temp.length >= 2){
// console.log(temp)
res.push([...temp]); // 此处必须使用扩展运算符...temp
// console.log(res)
}
}
return res;
};
19. js取整数、取余数的方法
取整
1)取整
// 丢弃小数部分,保留整数部分
parseInt(5/2) // 2
2)向上取整
// 向上取整,有小数就整数部分加1
Math.ceil(5/2) // 3
3)向下取整
// 向下取整,丢弃小数部分
Math.floor(5/2) // 2
4)四舍五入
// 四舍五入
Math.round(5/2) // 3
取余
// 取余
6%4 // 2
20. 分治算法(归并排序)
21. 平衡二叉树
22. Math对象
Math.min()用于确定一组数值中的最小值;
Math.max()用于确定一组数值中的最大值;
Math.ceil()执行向上舍入,即它总是将数值向上舍入为最接近的整数;
Math.floor()执行向下舍入,即它总是将数值向下舍入为最接近的整数;
Math.round()执行标准舍入,即它总是将数值四舍五入为最接近的整数;
Math.random()方法返回介于0到1之间一个随机数,不包括0和1;
Math.pow()获取一个值的多少次幂; // 例如:Math.pow(10,2) = 100;
Math.sqrt()对数值开方;
Math.PI 获取圆周率π 的值;
Math.abs()取绝对值。
23. 正则表达式
正则验证代码如下:
验证字母:/^[a-zA-Z]+$/
验证长度为3的字符:/^.{
3}$/
验证由26个英文字母组成的字符串:/^[A-Za-z]+$/
验证日期YYYY-MM-DD:/^(\d{
1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/
验证邮编:/^\d{
6}$/
验证日期格式YYYY-MM-DD hh:mm:ss:/^(\d{
1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/
验证整数:/^[-+]?\d*$/
验证小数:/^[-\+]?\d+(\.\d+)?$/
验证中文:/^[\u0391-\uFFE5]+$/
验证邮箱:/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
验证手机号:/^1[3456789]\d{
9}$/
验证身份证:/^\d{
6}(18|19|20)?\d{
2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{
3}(\d|X)$/
在线测试工具:https://regexr.com/
24. 递归与迭代
递归,程序反复调用自身即是递归。
做题方法,思考以下几点:
- 终止条件
- 返回值是什么
- 本级递归需要干什么
博客讲解:三道题套路解决递归问题
力扣题目:24. 两两交换链表中的节点、101. 对称二叉树、110. 平衡二叉树、104. 二叉树的最大深度、剑指 Offer 55 - I. 二叉树的深度、111. 二叉树的最小深度