链表

203. 移除链表元素

1
设置一个虚拟头结点,使得链表中所有元素的删除操作都统一

707. 设计链表

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
class MyLinkedList {
public:
// 定义链表节点结构体
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};

// 初始化链表
MyLinkedList() {
_dummyHead = new LinkedNode(0); // 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
_size = 0;
}

// 获取到第index个节点数值,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
int get(int index) {
if (index > (_size - 1) || index < 0) {
return -1;
}
LinkedNode* cur = _dummyHead->next;
while(index--){ // 如果--index 就会陷入死循环
cur = cur->next;
}
return cur->val;
}

// 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
void addAtHead(int val) {
LinkedNode* newNode = new LinkedNode(val);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}

// 在链表最后面添加一个节点
void addAtTail(int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newNode;
_size++;
}

// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果index大于链表的长度,则返回空
// 如果index小于0,则置为0,作为链表的新头节点。
void addAtIndex(int index, int val) {
if (index > _size || index < 0) {
return;
}
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(index--) {
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}

// 删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
void deleteAtIndex(int index) {
if (index >= _size || index < 0) {
return;
}
LinkedNode* cur = _dummyHead;
while(index--) {
cur = cur ->next;
}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
_size--;
}

// 打印链表
void printLinkedList() {
LinkedNode* cur = _dummyHead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
private:
int _size;
LinkedNode* _dummyHead;

};

206. 反转链表
双指针,把链表的指针翻转一下,其实就是不断把 cur 指向 pre 的过程,画图可理解

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
class Solution {

public:

ListNode* reverseList(ListNode* head) {

ListNode* temp;

ListNode* cur = head;

ListNode* pre = NULL;

while(cur){

temp = cur -> next;

cur -> next = pre;

pre = cur;

cur = temp;

}

return pre;



}

};

24. 两两交换链表中的节点
交换节点

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
class Solution {

public:

ListNode* swapPairs(ListNode* head) {

ListNode* dummyNode = new ListNode(0);

dummyNode -> next = head;

ListNode* cur = dummyNode;

while(cur -> next != nullptr && cur -> next -> next != nullptr){

ListNode* tmp = cur->next;

ListNode* tmp1 = cur->next->next->next; // 记录临时节点



cur->next = cur -> next -> next;

cur -> next -> next = tmp;

cur -> next -> next -> next = tmp1;



cur = cur->next->next; // cur移动两位,准备下一轮交换

}

return dummyNode -> next;

}

};

19. 删除链表的倒数第 N 个结点

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
class Solution {

public:

ListNode* removeNthFromEnd(ListNode* head, int n) {

ListNode* dummyHead = new ListNode(0);

dummyHead -> next = head;

ListNode* fast = dummyHead;

ListNode* slow = dummyHead;



while(n-- && fast != NULL){

fast = fast -> next;

}



fast = fast -> next; // fast 移动 n + 1


while(fast != NULL){

fast = fast -> next;

slow = slow -> next;

}

slow -> next = slow -> next -> next;
// ListNode *tmp = slow->next; C++释放内存的逻辑
// slow->next = tmp->next;
// delete nth;
return dummyHead -> next;

}

};

面试题 02.07. 链表相交
简单题,只要将 A 移动到 与 B 的开端同步时,指针不断加一,判断 A B指向的节点是否相等即可

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class Solution {

public:

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {

ListNode* curA = headA;

ListNode* curB = headB;

int lenA = 0, lenB = 0;

//求A B长度

while(curA != NULL){

lenA ++;

curA = curA -> next;

}

while(curB != NULL){

lenB ++;

curB = curB -> next;

}

curA = headA;

curB = headB;

// 使得 A 是较长的那个链表

if(lenA < lenB){

swap(lenA,lenB);

swap(curA,curB);

}



int gap = lenA - lenB;

// A 移动,与 B 齐平

while(gap --){

curA = curA -> next;

}



while(curA && curB){

if(curA == curB){

return curA;

}

curA = curA -> next;

curB = curB -> next;

}

return NULL;

}

};

142. 环形链表 II
定义快慢指针,快指针一次走两步,慢指针一次走一步,如果有环,则快慢指针一定在环内相遇
记录下它们的相遇节点,头节点和相遇节点同时移动,它们的相遇点就是环的入口

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
class Solution {

public:

ListNode *detectCycle(ListNode *head) {

ListNode* fast = head;

ListNode* slow = head;



while(fast != NULL && fast -> next != NULL){

fast = fast -> next -> next;

slow = slow -> next;



if(fast == slow){

ListNode* index2 = fast;

ListNode* index1 = head;

while(index1 != index2){

index1 = index1 -> next;

index2 = index2 -> next;

}

return index1;

}

}

return NULL;

}

};