0%

链表(List)

链表(List)

定义

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

实现

1
2
3
4
function ListNode(value) {
this.value = value;
this.nextNode = null;
}

应用

236.二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4]

1
2
3
4
5
6
7
     3
/ \
5 1
/ \ / \
6 2 0 8
/ \
7 4

示例 1:

1
2
3
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

示例 2:

1
2
3
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
* 方法:记录父节点
* 细节:拿到子节点的同时给子节点赋值father属性记录回溯链表。
* 空间复杂度:On
* 时间复杂度:On
*/
var lowestCommonAncestor = function (root, p, q) {
function setNodeList(node) {
let list = [node];
while (node && node.father) {
list.unshift(node.father);
node = node.father;
}
return list
}

let nodeStack = [root];
let nodeListP = undefined;
let nodeListQ = undefined;

while (nodeStack.length) {
let node = nodeStack.pop();
if (node.right) {
nodeStack.push(node.right);
node.right.father = node;
}
if (node.left) {
nodeStack.push(node.left);
node.left.father = node;
}
if (node.val === q.val) {
nodeListQ = setNodeList(node);
}
if (node.val === p.val) {
nodeListP = setNodeList(node);
}
if (nodeListP && nodeListQ) {
break;
}
}
for (let i = 0; i < Math.min(nodeListP.length, nodeListQ.length); i++) {
if (!nodeListP[i + 1] || !nodeListQ[i + 1] || nodeListP[i + 1].val !== nodeListQ[i + 1].val) {
return nodeListP[i];
}
}
return null;
};