Skip to content

Commit 2b36c5d

Browse files
committed
art update: heap
1 parent 48e6628 commit 2b36c5d

10 files changed

+628
-10
lines changed

docs/.vuepress/config.js

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,18 @@
11
module.exports = {
22
title: 'awesome-coding-js',
33
description: '用JavaScript实现的算法和数据结构',
4+
base: '/docs/',
45
themeConfig: {
56
sidebarDepth: 2,
67
lastUpdated: 'Last Updated',
78
nav: [
89
{ text: '数据结构分类', link: '/dataStructure/' },
9-
{ text: '博客', link: 'http://www.conardli.top' },
10+
{ text: '博客', link: 'http://www.conardli.top/blog/article/' },
1011
{ text: 'github', link: 'https://github.com/ConardLi' },
1112
],
1213
sidebar: {
1314
'/dataStructure/': [
1415
'/dataStructure/',
15-
{
16-
title: '堆',
17-
children: [
18-
'/dataStructure/堆/堆的基本操作',
19-
'/dataStructure/堆/数据流中的中位数',
20-
'/dataStructure/堆/最小的k个数',
21-
]
22-
},
2316
{
2417
title: '二叉树',
2518
children: [
@@ -41,7 +34,29 @@ module.exports = {
4134
'/dataStructure/二叉树/二叉树的下一个节点',
4235
'/dataStructure/二叉树/树的子结构',
4336
]
44-
}
37+
},
38+
{
39+
title: '堆',
40+
children: [
41+
'/dataStructure/堆/堆的基本操作',
42+
'/dataStructure/堆/数据流中的中位数',
43+
'/dataStructure/堆/最小的k个数',
44+
]
45+
},
46+
{
47+
title: '链表',
48+
children: [
49+
'/dataStructure/链表/从尾到头打印链表',
50+
'/dataStructure/链表/反转链表',
51+
'/dataStructure/链表/复杂链表的复制',
52+
'/dataStructure/链表/合并两个排序的链表',
53+
'/dataStructure/链表/链表倒数第k个节点',
54+
'/dataStructure/链表/链表中环的入口节点',
55+
'/dataStructure/链表/两个链表的第一个公共节点',
56+
'/dataStructure/链表/圈圈中最后剩下的数字',
57+
'/dataStructure/链表/删除链表中的节点or重复的节点',
58+
]
59+
},
4560
]
4661
}
4762
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
{
3+
"title": "两个链表的第一个公共节点",
4+
}
5+
---
6+
## 题目
7+
8+
输入两个链表,找出它们的第一个公共结点。
9+
10+
## 思路
11+
12+
13+
- 1.先找到两个链表的长度`length1``length2`
14+
15+
- 2.让长一点的链表先走`length2-length1`步,让长链表和短链表起点相同
16+
17+
- 3.两个链表一起前进,比较获得第一个相等的节点
18+
19+
- 时间复杂度`O(length1+length2)` 空间复杂度`O(0)`
20+
21+
![](/dist/img/链表公共节点.png)
22+
23+
24+
## 代码
25+
26+
```js
27+
function FindFirstCommonNode(pHead1, pHead2) {
28+
if (!pHead1 || !pHead2) { return null; }
29+
// 获取链表长度
30+
let length1 = getLength(pHead1);
31+
let length2 = getLength(pHead2);
32+
// 长链表先行
33+
let lang, short, interval;
34+
if (length1 > length2) {
35+
lang = pHead1;
36+
short = pHead2;
37+
interval = length1 - length2;
38+
} else {
39+
lang = pHead2;
40+
short = pHead1;
41+
interval = length2 - length1;
42+
}
43+
while (interval--) {
44+
lang = lang.next;
45+
}
46+
// 找相同节点
47+
while (lang) {
48+
if (lang === short) {
49+
return lang;
50+
}
51+
lang = lang.next;
52+
short = short.next;
53+
}
54+
return null;
55+
}
56+
57+
function getLength(head) {
58+
let current = head;
59+
let result = 0;
60+
while (current) {
61+
result++;
62+
current = current.next;
63+
}
64+
return result;
65+
}
66+
```
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
{
3+
"title": "从尾到头打印链表",
4+
}
5+
---
6+
7+
8+
## 题目
9+
10+
输入一个链表,按链表值从尾到头的顺序返回一个`ArrayList`
11+
12+
## 分析
13+
14+
要了解链表的数据结构:
15+
16+
`val`属性存储当前的值,`next`属性存储下一个节点的引用。
17+
18+
要遍历链表就是不断找到当前节点的`next`节点,当`next`节点是`null`时,说明是最后一个节点,停止遍历。
19+
20+
因为是从尾到头的顺序,使用一个队列来存储打印结果,每次从队列头部插入。
21+
22+
## 代码
23+
24+
```js
25+
/*function ListNode(x){
26+
this.val = x;
27+
this.next = null;
28+
}*/
29+
function printListFromTailToHead(head)
30+
{
31+
const array = [];
32+
while(head){
33+
array.unshift(head.val);
34+
head = head.next;
35+
}
36+
return array;
37+
}
38+
```
39+
40+
## 考察点
41+
42+
- 链表
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
{
3+
"title": "删除链表中的节点or重复的节点",
4+
}
5+
---
6+
7+
## 删除链表中的节点
8+
9+
给定单链表的头指针和要删除的指针节点,在O(1)时间内删除该节点。
10+
11+
- 1.删除的节点不是尾部节点 - 将next节点覆盖当前节点
12+
- 2.删除的节点是尾部节点且等于头节点,只剩一个节点 - 将头节点置为null
13+
- 3.删除的节点是尾节点且前面还有节点 - 遍历到末尾的前一个节点删除
14+
15+
只有第三种情况时间复杂度是O(n),且这种情况只会出现1/n次,所以算法时间复杂度是O(1)
16+
```js
17+
var deleteNode = function (head, node) {
18+
if (node.next) {
19+
node.val = node.next.val;
20+
node.next = node.next.next;
21+
} else if (node === head) {
22+
node = null;
23+
head = null;
24+
} else {
25+
node = head;
26+
while (node.next.next) {
27+
node = node.next;
28+
}
29+
node.next = null;
30+
node = null;
31+
}
32+
return node;
33+
};
34+
```
35+
36+
## 删除链表中重复的节点
37+
38+
### 方法1.存储链表中元素出现的次数
39+
40+
- 1.用一个map存储每个节点出现的次数
41+
- 2.删除出现次数大于1的节点
42+
43+
此方法删除节点时可以使用上面总结的办法。
44+
45+
时间复杂度:O(n)
46+
47+
空间复杂度:O(n)
48+
49+
```js
50+
function deleteDuplication(pHead) {
51+
const map = {};
52+
if (pHead && pHead.next) {
53+
let current = pHead;
54+
// 计数
55+
while (current) {
56+
const val = map[current.val];
57+
map[current.val] = val ? val + 1 : 1;
58+
current = current.next;
59+
}
60+
current = pHead;
61+
while (current) {
62+
const val = map[current.val];
63+
if (val > 1) {
64+
// 删除节点
65+
console.log(val);
66+
if (current.next) {
67+
current.val = current.next.val;
68+
current.next = current.next.next;
69+
} else if (current === pHead) {
70+
current = null;
71+
pHead = null;
72+
} else {
73+
current = pHead;
74+
while (current.next.next) {
75+
current = current.next;
76+
}
77+
current.next = null;
78+
current = null;
79+
}
80+
81+
} else {
82+
current = current.next;
83+
}
84+
}
85+
}
86+
return pHead;
87+
}
88+
```
89+
90+
91+
### 方法2.重新比较连接数组
92+
93+
94+
链表是排好顺序的,所以重复元素都会相邻出现
95+
递归链表:
96+
- 1.当前节点或当前节点的next为空,返回该节点
97+
- 2.当前节点是重复节点:找到后面第一个不重复的节点
98+
- 3.当前节点不重复:将当前的节点的next赋值为下一个不重复的节点
99+
100+
```js
101+
function deleteDuplication(pHead) {
102+
if (!pHead || !pHead.next) {
103+
return pHead;
104+
} else if (pHead.val === pHead.next.val) {
105+
let tempNode = pHead.next;
106+
while (tempNode && pHead.val === tempNode.val) {
107+
tempNode = tempNode.next;
108+
}
109+
return deleteDuplication(tempNode);
110+
} else {
111+
pHead.next = deleteDuplication(pHead.next);
112+
return pHead;
113+
}
114+
}
115+
```
116+
117+
118+
时间复杂度:O(n)
119+
120+
空间复杂度:O(1)
121+
122+
123+
## 考察点
124+
125+
- 链表
126+
- 考虑问题的全面性
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
{
3+
"title": "反转链表",
4+
}
5+
---
6+
7+
## 反转链表
8+
9+
输入一个链表,反转链表后,输出新链表的表头。
10+
11+
## 思路
12+
13+
以链表的头部节点为基准节点
14+
15+
将基准节点的下一个节点挪到头部作为头节点
16+
17+
当基准节点的`next``null`,则其已经成为最后一个节点,链表已经反转完成
18+
19+
## 代码
20+
21+
```js
22+
var reverseList = function (head) {
23+
let currentNode = null;
24+
let headNode = head;
25+
while (head && head.next) {
26+
currentNode = head.next;
27+
head.next = currentNode.next;
28+
currentNode.next = headNode;
29+
headNode = currentNode;
30+
}
31+
return headNode;
32+
};
33+
```
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
{
3+
"title": "合并两个排序的链表",
4+
}
5+
---
6+
## 题目
7+
8+
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
9+
10+
## 思路
11+
12+
![image](../../dist/img/合并链表.png)
13+
14+
链表头部节点比较,取较小节点。
15+
16+
小节点的next等于小节点的next和大节点的较小值。
17+
18+
如此递归。
19+
20+
返回小节点。
21+
22+
考虑代码的鲁棒性,也是递归的终止条件,两个head为null的情况,取对方节点返回。
23+
24+
## 代码
25+
26+
```js
27+
function Merge(pHead1, pHead2) {
28+
if (!pHead1) {
29+
return pHead2;
30+
}
31+
if (!pHead2) {
32+
return pHead1;
33+
}
34+
let head;
35+
if (pHead1.val < pHead2.val) {
36+
head = pHead1;
37+
head.next = Merge(pHead1.next, pHead2);
38+
} else {
39+
head = pHead2;
40+
head.next = Merge(pHead1, pHead2.next);
41+
}
42+
return head;
43+
}
44+
```
45+

0 commit comments

Comments
 (0)