Skip to content

Commit b3260bb

Browse files
feat: update
1 parent 5fba181 commit b3260bb

32 files changed

+2622
-141
lines changed

docs/.vuepress/config.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ const ArrayList = GeneratorMenu('/algorithm/数组/', [
6868
'螺旋矩阵II',
6969
'三数之和',
7070
'更接近的三数之和',
71+
'合并区间',
72+
'区间列表的交集',
73+
'删除被覆盖区间',
7174
]);
7275
const TreeList = GeneratorMenu('/algorithm/树/', [
7376
'树的遍历',
@@ -154,6 +157,8 @@ module.exports = {
154157
['/algorithm/动态规划/最大子序和', '最大子序和'],
155158
['/algorithm/动态规划/最长公共前缀', '最长公共前缀'],
156159
['/algorithm/动态规划/最长回文子串', '最长回文子串'],
160+
['/algorithm/动态规划/最长公共子序列', '最长公共子序列'],
161+
['/algorithm/动态规划/最长上升子序列', '最长上升子序列'],
157162
['/algorithm/动态规划/打家劫舍', '打家劫舍'],
158163
['/algorithm/动态规划/打家劫舍II', '打家劫舍 II'],
159164
['/algorithm/动态规划/打家劫舍III', '打家劫舍 III'],
@@ -171,11 +176,13 @@ module.exports = {
171176
['/jsCode/实现一个Promise', '实现一个Promise'],
172177
['/jsCode/实现一个new', '实现一个new'],
173178
['/jsCode/实现instanceof', '实现instanceof'],
179+
['/jsCode/实现flat', '实现flat'],
174180
['/jsCode/手写继承', '手写继承'],
175181
['/jsCode/实现一个async函数', '实现一个async函数'],
176182
['/jsCode/实现一个iterator', '实现一个iterator'],
177183
['/jsCode/setTimeout实现setInterval', 'setTimeout实现setInterval'],
178184
['/jsCode/限制并发请求', '限制并发请求'],
185+
['/jsCode/实现一个repeat方法', '实现一个repeat方法'],
179186
['/jsCode/简单实现一个Vue的双向绑定', '简单实现一个Vue的双向绑定'],
180187
['/jsCode/实现一个vue自定义指令-懒加载', '实现一个vue自定义指令-懒加载'],
181188
['/jsCode/实现一个轮播图', '实现一个轮播图'],

docs/algorithm/README.md

Lines changed: 73 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,83 @@
1-
21
###
3-
- [树的遍历(DFS和BFS)](./树/树的遍历.md)
4-
- [路径总和(I、II、III)](./树/路径总和.md)
5-
- [相同的树](./树/相同的树.md)
6-
- [对称二叉树](./树/对称二叉树.md)
7-
- [翻转二叉树](./树/翻转二叉树.md)
8-
- [另一个树的子树](./树/另一个树的子树.md)
9-
- [验证二叉搜索树](./树/验证二叉搜索树.md)
10-
- [二叉树的最大深度](./树/二叉树的最大深度.md)
11-
- [二叉树的最小深度](./树/二叉树的最小深度.md)
12-
- [平衡二叉树](./树/平衡二叉树.md)
13-
- [将有序数组转换为二叉搜索树](./树/将有序数组转换为二叉搜索树.md)
14-
- [二叉搜索树迭代器](./树/二叉搜索树迭代器.md)
15-
- [二叉搜索树的最近公共祖先](./树/二叉搜索树的最近公共祖先.md)
16-
- [二叉树的最近公共祖先](./树/二叉树的最近公共祖先.md)
2+
3+
- [树的遍历(DFS 和 BFS)](./树/树的遍历.md)
4+
- [路径总和(I、II、III)](./树/路径总和.md)
5+
- [相同的树](./树/相同的树.md)
6+
- [对称二叉树](./树/对称二叉树.md)
7+
- [翻转二叉树](./树/翻转二叉树.md)
8+
- [另一个树的子树](./树/另一个树的子树.md)
9+
- [验证二叉搜索树](./树/验证二叉搜索树.md)
10+
- [二叉树的最大深度](./树/二叉树的最大深度.md)
11+
- [二叉树的最小深度](./树/二叉树的最小深度.md)
12+
- [平衡二叉树](./树/平衡二叉树.md)
13+
- [将有序数组转换为二叉搜索树](./树/将有序数组转换为二叉搜索树.md)
14+
- [二叉搜索树迭代器](./树/二叉搜索树迭代器.md)
15+
- [二叉搜索树的最近公共祖先](./树/二叉搜索树的最近公共祖先.md)
16+
- [二叉树的最近公共祖先](./树/二叉树的最近公共祖先.md)
17+
1718
### 链表
18-
- [反转链表](./链表/反转链表.md)
19-
- [回文链表](./链表/回文链表.md)
20-
- [倒数第K个节点](./链表/倒数第K个节点.md)
21-
- [合并两个有序链表](./链表/合并两个有序链表.md)
22-
- [两个链表的第一个公共节点](./链表/两个链表的第一个公共节点.md)
23-
- [找出链表的中间节点](./链表/找出链表的中间节点.md)
19+
20+
- [反转链表](./链表/反转链表.md)
21+
- [回文链表](./链表/回文链表.md)
22+
- [倒数第 K 个节点](./链表/倒数第K个节点.md)
23+
- [合并两个有序链表](./链表/合并两个有序链表.md)
24+
- [两个链表的第一个公共节点](./链表/两个链表的第一个公共节点.md)
25+
- [找出链表的中间节点](./链表/找出链表的中间节点.md)
26+
2427
### 数组
25-
- [打乱数组](./数组/打乱数组.md)
26-
- [构建乘积数组](./数组/构建乘积数组.md)
27-
- [扑克牌中的顺子](./数组/扑克牌中的顺子.md)
28-
- [使数组唯一的最小增量](./数组/使数组唯一的最小增量.md)
29-
- [数组的交集](./数组/数组的交集.md)
30-
- [数组的交集II](./数组/数组的交集II.md)
31-
- [合并两个有序数组](./数组/合并两个有序数组.md)
32-
- [数组中的第K个最大元素](./数组/数组中的第K个最大元素.md)
33-
- [螺旋矩阵](./数组/螺旋矩阵.md)
34-
- [螺旋矩阵 II](./数组/螺旋矩阵II.md)
35-
- [螺旋矩阵 II](./数组/螺旋矩阵II.md)
36-
- [三数之和](./数组/三数之和.md)
37-
- [更接近的三数之和](./数组/更接近的三数之和.md)
28+
29+
- [打乱数组](./数组/打乱数组.md)
30+
- [构建乘积数组](./数组/构建乘积数组.md)
31+
- [扑克牌中的顺子](./数组/扑克牌中的顺子.md)
32+
- [使数组唯一的最小增量](./数组/使数组唯一的最小增量.md)
33+
- [数组的交集](./数组/数组的交集.md)
34+
- [数组的交集 II](./数组/数组的交集II.md)
35+
- [合并两个有序数组](./数组/合并两个有序数组.md)
36+
- [数组中的第 K 个最大元素](./数组/数组中的第K个最大元素.md)
37+
- [螺旋矩阵](./数组/螺旋矩阵.md)
38+
- [螺旋矩阵 II](./数组/螺旋矩阵II.md)
39+
- [螺旋矩阵 II](./数组/螺旋矩阵II.md)
40+
- [三数之和](./数组/三数之和.md)
41+
- [更接近的三数之和](./数组/更接近的三数之和.md)
42+
3843
### 字符串
39-
- [反转字符串](./字符串/反转字符串.md)
40-
- [反转字符串II](./字符串/反转字符串II.md)
41-
- [反转字符串中的单词 III](./字符串/反转字符串中的单词III.md)
42-
- [字符串相乘](./字符串/字符串相乘.md)
43-
44+
45+
- [反转字符串](./字符串/反转字符串.md)
46+
- [反转字符串 II](./字符串/反转字符串II.md)
47+
- [反转字符串中的单词 III](./字符串/反转字符串中的单词III.md)
48+
- [字符串相乘](./字符串/字符串相乘.md)
49+
4450
### 数学
45-
- [计算质数](./数学/计算质数.md)
46-
- [求众数](./数学/求众数.md)
47-
- [中位数](./数学/中位数.md)
48-
- [只出现一次的数字](./数学/只出现一次的数字.md)
49-
- [有效的三角形个数](./数学/有效的三角形个数.md)
50-
51+
52+
- [计算质数](./数学/计算质数.md)
53+
- [求众数](./数学/求众数.md)
54+
- [中位数](./数学/中位数.md)
55+
- [只出现一次的数字](./数学/只出现一次的数字.md)
56+
- [有效的三角形个数](./数学/有效的三角形个数.md)
5157

5258
### 动态规划
53-
- [斐波那契数列](./动态规划/斐波那契数列.md)
54-
- [买卖股票的最佳时机I](./动态规划/买卖股票的最佳时机I.md)
55-
- [买卖股票的最佳时机II](./动态规划/买卖股票的最佳时机II.md)
56-
- [盛最多水的容器](./动态规划/盛最多水的容器.md)
57-
- [无重复字符的最长子串](./动态规划/无重复字符的最长子串.md)
58-
- [最大子序和](./动态规划/最大子序和.md)
59-
- [最长公共前缀](./动态规划/最长公共前缀.md)
60-
- [最长回文子串](./动态规划/最长回文子串.md)
61-
- [打家劫舍](./动态规划/打家劫舍.md)
62-
- [打家劫舍 II](./动态规划/打家劫舍II.md)
63-
- [打家劫舍 III](./动态规划/打家劫舍III.md)
6459

60+
- [斐波那契数列](./动态规划/斐波那契数列.md)
61+
- [买卖股票的最佳时机 I](./动态规划/买卖股票的最佳时机I.md)
62+
- [买卖股票的最佳时机 II](./动态规划/买卖股票的最佳时机II.md)
63+
- [盛最多水的容器](./动态规划/盛最多水的容器.md)
64+
- [无重复字符的最长子串](./动态规划/无重复字符的最长子串.md)
65+
- [最大子序和](./动态规划/最大子序和.md)
66+
- [最长公共前缀](./动态规划/最长公共前缀.md)
67+
- [最长回文子串](./动态规划/最长回文子串.md)
68+
- [打家劫舍](./动态规划/打家劫舍.md)
69+
- [打家劫舍 II](./动态规划/打家劫舍II.md)
70+
- [打家劫舍 III](./动态规划/打家劫舍III.md)
6571

6672
### 推荐好的书籍和博客
67-
- [fucking-algorithm](https://labuladong.gitbook.io/algo/)
68-
- [LeetCodeAnimation](https://github.com/MisterBooo/LeetCodeAnimation)
69-
- 学习JavaScript数据结构与算法(第2版)
70-
- 算法图解
71-
- 剑指offer
73+
74+
- [fucking-algorithm](https://labuladong.gitbook.io/algo/)
75+
- [LeetCodeAnimation](https://github.com/MisterBooo/LeetCodeAnimation)
76+
- [labuladong 的算法小抄](https://labuladong.github.io/algo/)
77+
- 学习 JavaScript 数据结构与算法(第 2 版)
78+
- 算法图解
79+
- 剑指 offer
80+
81+
### 声明
82+
83+
这部分的算法题解大部分都是看的官方的题解还有上面提到的一些书籍和博客,并非原创,只用于自己学习和复习。如果有涉及到版权问题,请联系作者删除。

docs/algorithm/其他/二分查找.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
## 二分搜索
2+
3+
- 寻找一个数(基本的二分搜索)
4+
- 寻找左侧边界
5+
- 寻找右侧边界
6+
7+
二分搜索框架
8+
9+
```js
10+
function binarySearch(nums, target) {
11+
let left = 0;
12+
let right = ...;
13+
14+
while(...) {
15+
let mid = left + (right - left) / 2;
16+
if (nums[mid] == target) {
17+
...
18+
} else if (nums[mid] < target) {
19+
left = ...
20+
} else if (nums[mid] > target) {
21+
right = ...
22+
}
23+
}
24+
return ...;
25+
}
26+
27+
```
28+
29+
`...` 标记的部分,就是可能出现细节问题的地方.
30+
计算 mid 时需要防止溢出,代码中 `left + (right - left) / 2` 就和 `(left + right) / 2` 的结果相同,但是有效防止了 `left``right` 太大,直接相加导致溢出的情况。
31+
32+
1. 搜索一个数,如果存在,返回其索引,否则返回 -1。
33+
34+
```js
35+
// 寻找一个数(基本的二分搜索)
36+
function binarySearch(nums, target) {
37+
let left = 0;
38+
let right = nums.length - 1; // 注意
39+
40+
while (left <= right) {
41+
let mid = Math.floor(left + (right - left) / 2);
42+
if (nums[mid] == target) {
43+
return mid;
44+
} else if (nums[mid] < target) {
45+
left = mid + 1; // // 注意
46+
} else if (nums[mid] > target) {
47+
right = mid - 1; // 注意
48+
}
49+
}
50+
return -1;
51+
}
52+
```
53+
54+
- 为什么 while 循环的条件中是 <=,而不是 <?
55+
- 因为初始化 right 的赋值是 nums.length - 1,即最后一个元素的索引,而不是 nums.length。[left, right] 两端都闭的区间。这个区间其实就是每次进行搜索的区间。
56+
57+
2. 寻找左侧边界的二分搜索
58+
59+
```js
60+
function searchLeftBound(arr, target) {
61+
let left = 0;
62+
let right = arr.length - 1;
63+
while (left <= right) {
64+
const mid = Math.floor((left + right) / 2);
65+
if (arr[mid] === target) {
66+
// 收缩右侧边界
67+
right = mid - 1;
68+
} else if (arr[mid] < target) {
69+
left = mid + 1;
70+
} else if (arr[mid] > target) {
71+
right = mid - 1;
72+
}
73+
}
74+
// 检查出界情况
75+
if (left >= nums.length || nums[left] != target) {
76+
return -1;
77+
}
78+
return left;
79+
}
80+
```
81+
82+
3. 寻找右侧边界的二分查找:
83+
84+
```js
85+
function searchRightBound(arr, target) {
86+
let left = 0;
87+
let right = arr.length - 1;
88+
while (left <= right) {
89+
const mid = Math.floor((left + right) / 2);
90+
if (arr[mid] === target) {
91+
left = mid + 1;
92+
} else if (arr[mid] < target) {
93+
left = mid + 1;
94+
} else if (arr[mid] > target) {
95+
right = mid - 1;
96+
}
97+
}
98+
// 最后要检查 right 越界的情况
99+
if (right < 0 || nums[right] != target) {
100+
return -1;
101+
}
102+
return right;
103+
}
104+
```
105+
106+
### 对应题目
107+
108+
- 704. 二分查找
109+
- 34. 在排序数组中查找元素的第一个和最后一个位置
110+
111+
## 二分查找的运用
112+
113+
上面提到的二分搜索框架仅仅局限于【在有序数组中搜索指定元素】这个场景,但是具体的算法问题没有这么直接,可能很难看出这个问题能够遇到二分搜索。
114+
115+
下面总结二分搜索运用的框架套路。
116+
117+
原始的二分搜索
118+
119+
- 【有序数组】中搜索一个元素 target, 返回 index;不存在,返回特殊值(根据题目要求)
120+
- 【有序数组】中存在多个 target 元素。这些肯定都挨着,那就是返回最左侧或者最右侧的 target。即【搜索左侧边界】和【搜索右侧边界】。这是比较常用的场景。
121+
122+
算法题一般都要求求最值。比如让你求吃香蕉的「最小速度」,让你求轮船的「最低运载能力」,求最值的过程,必然是搜索一个边界的过程,所以后面我们就详细分析一下这两种搜索边界的二分算法代码。
123+
124+
### 题目
125+
126+
- 875. 爱吃香蕉的珂珂
127+
- 1011. 在 D 天内送达包裹的能力
128+
- 410. 分割数组的最大值
129+
130+
爱吃香蕉的珂珂
131+
首先要理解题目。最后一步步分析,它是怎么和二分搜索联系起来的
132+
133+
- 总时间为 totalHour,速度为 k
134+
- 珂珂 1 小时能吃 k 个:但如果一堆少于 k 个,那也得花一小时 (一小时到了,才吃下一堆)
135+
136+
```js
137+
if (piles[i] < k) {
138+
totalHour += 1;
139+
}
140+
```
141+
142+
- 如果 1 堆大于 k 个,那么超过 k 的部分也算 1 小时。(例如,一堆 10 个,k=3 时,珂珂花 3 小时吃了 9 个,剩下的 1 个也算 1 小时,也就是总用时 4 小时)
143+
144+
```js
145+
if (piles[i] < k) {
146+
totalHour += 1;
147+
}
148+
```
149+
150+
## 参考
151+
152+
- [二分搜索框架](https://labuladong.github.io/algo/2/18/26/)
153+
- [二分搜索运用框架](https://mp.weixin.qq.com/s/JgJ0jh2SJd6grQSPnN6Jww)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
48. 旋转图像
2+
3+
要点
4+
5+
1. 左上角和右下角镜像对称
6+
2. 对 1 得到的产物,再做每行的翻转。
7+
8+
==
9+
10+
54. 螺旋矩阵
11+
要点
12+
13+
1. 4 个变量,来控制上下左右 4 个边界,随着每轮循环,边界会跟着变化
14+
1. direction 来表示方向,判断 1 中的边界是否要修改方向,修改方向的时候同时修改边界
15+
1. `m * n` 循环,`result.push(matix[i][j])`
16+
17+
==
18+
19+
59. 螺旋矩阵 II
20+
要点:跟 54 一样,不同的是,是给 `result[i][j] = k`
21+
22+
## 参考
23+
24+
- [二维数组的花式遍历技巧](https://labuladong.github.io/algo/2/18/24/)

0 commit comments

Comments
 (0)