24. 两两交换链表中的节点
1. LeetCode链接
https://leetcode.cn/problems/swap-nodes-in-pairs/submissions/489195706/
2. 题目描述
3. 想法
先考虑头节点会不会变,此题明显会变,所以最好使用虚拟头节点。
两两交换,涉及到三个节点要改变其next指针。
pre、cur、post三个的next都要动。
所以每次循环可以记录这三个指针。依次从后往前改变next指针。
循环判断比较关键。例如,我就碰到这种错误
Line 20: Char 21: runtime error: member access within null pointer of type 'ListNode' (solution.cpp)
原因在于我的判断为while(cur->next != NULL),忽略了cur本身有可能已经是NULL了。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* cur = head;
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* pre = dummyHead;
ListNode* post = head;
while (cur != NULL && cur->next != NULL) {
post = cur->next;
cur->next = post->next;
post->next = cur;
pre->next = post;
pre = cur;
cur = cur->next;
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
19. 删除链表的倒数第N个节点
1. LeetCode链接
https://leetcode.cn/problems/remove-nth-node-from-end-of-list/submissions/489197897/
2. 题目描述
3. 想法
最后一个节点的前面第N-1个节点是要删除的,根据这个特点,只要设置两个指针,间隔距离N,当后面的指针到达最后,那么前面的指针所指的恰好是我们要删除的。
这里的细节是,删除操作,最好是记录想删除节点的前一个,删起来更方便。
我碰到如下错误。原因在于又没有考虑头节点是否会变。因为实际情况是头节点也有可能被删除,所以要搞个虚拟头节点。这么做既方便删除,也能找准head。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* post = head;
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
for (; n > 0; n--) post = post->next;
while (post != NULL) {
post = post->next;
cur = cur->next;
}
ListNode* temp = cur->next;
cur->next = temp->next;
delete temp;
head = dummyHead->next; // 易忽略代码
delete dummyHead;
return head;
}
};
面试题 02.07. 链表相交
1. LeetCode链接
https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/description/
2. 题目描述
3. 想法
这个题目的特点为,两个链表尾端对齐,也就是说,如果有一长一短两个链表,长链表的长出部分必不可能是相交节点。而相同长度的链表,同时同步从head往后找,一定能找到相交节点。
先求两个链表各自的长度,走完长链表的长出部分,然后再同时同步走即可。
注意,是相同节点,而不是相同val值。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int i = 0, j = 0;
ListNode* a = headA;
ListNode* b = headB;
while (a != NULL) {
a = a->next;
i++;
}
while (b != NULL) {
b = b->next;
j++;
}
if (i < j) {
a = headB;
b = headA;
} else {
a = headA;
b = headB;
}
for (int n = abs(i - j); n > 0; n--) a = a->next;
while (a != NULL) {
if (a == b) return a;
a = a->next;
b = b->next;
}
return NULL;
}
};
142. 环形链表
1. LeetCode链接
https://leetcode.cn/problems/linked-list-cycle-ii/
2. 题目描述
3. 想法
纯数学,环追击问题。fast和slow。fast每次走两格,slow每次走一格。根据追及相遇时所用步数可以推断出很多东西。
这里要注意是slow先动还是fast先动。slow先动写起来更简单。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (head == NULL || head->next == NULL) return NULL;
ListNode* fast = head;
ListNode* slow = head;
int i = 0;
while (fast != NULL && fast->next != NULL) {
if (i != 0 && slow == fast) break;
i++;
slow = slow->next;
fast = fast->next->next;
}
if (fast == NULL || fast->next == NULL) return NULL;
fast = head;
while (fast != slow) {
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
总结:
1. 先考虑是否需要dummyHead,比如head会变的情况下,需要。
2. 注意避免NULL->next。