代码随想录算法训练营 Day4
- 知识点
- 链表提高
- 快慢指针+链表
24. 两两交换链表中的节点
- 思路/关键点:
- 何时终止遍历?
- 偶数:cur→next = NULL
- 奇数:cur→next→next = NULL
- 交换节点细节:
- 问题:空指针、循环异常
- 问题:空指针、循环异常
- 何时终止遍历?
- 答案:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode *dummy = new ListNode(0);
dummy->next = head;
ListNode *cur = dummy;
/* 循环终止条件:偶数 cur->next == NULL, 奇数 cur->next->next==NULL*/
while (cur->next != NULL && cur->next->next != NULL) {
/* 步骤一 */
ListNode *tmp = cur->next;
cur->next = cur->next->next;
/* 步骤二 */
ListNode *tmp1 = cur->next->next;
cur->next->next = tmp;
/* 步骤三 */
tmp->next = tmp1;
/* 更新cur指针 */
cur = cur->next->next;
}
return dummy->next;
}
};
19.删除链表的倒数第N个节点
代码随想录链接:
题目链接
文章讲解
视频讲解
重点:双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点
- 暴力法:
遍历求链表大小,再遍历直接删除
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *dummy = new ListNode(0);
dummy->next = head;
ListNode *cur = dummy->next;
int flag = 0;
while (cur != NULL) {
flag++;
cur = cur->next;
}
cur = dummy;
flag = flag - n;
while (flag--) {
cur = cur->next;
}
// 如果n是1,则cur->next->next可能不存在
ListNode *tmp = cur->next;
if (n != 1)
cur->next = cur->next->next;
else cur->next = nullptr;
delete tmp;
return dummy->next;
}
};
- 双指针
类比游标卡尺(同时移动fast和slow,两指针间距保持不变):
fast先走n+1步,slow指针再和fast指针同时移动,快指针走到最后一个节点(fast→next == NULL)的时候,慢指针正好走到要删除的节点的前一个节点
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *dummy = new ListNode(0);
dummy->next = head;
ListNode *fast = dummy->next;
ListNode *slow = dummy;
int flag = n;
while (n-- && fast != NULL)
fast = fast->next;
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
// 这里只是把fast当tmp用
fast = slow->next;
slow->next = slow->next->next;
delete fast;
return dummy->next;
}
};
160. 相交链表
- 思路:
如果中间有节点相同,那么从第一个相同节点到最后一个节点:两链表的节点完全相同,将指针右对齐。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *cur_a = headA;
ListNode *cur_b = headB;
int sizeA = 0, sizeB = 0;
// 节点相同,并不是节点的val相同,直接比较指针(内存地址)
while (cur_a != NULL) {
sizeA++;
cur_a = cur_a->next;
}
while (cur_b != NULL) {
sizeB++;
cur_b = cur_b->next;
}
cur_a = headA;
cur_b = headB;
if (sizeB > sizeA) {
swap(cur_a, cur_b);
swap(sizeA, sizeB);
}
int gap = sizeA - sizeB;
while (gap--) {
cur_a = cur_a->next;
}
while (cur_a != NULL) {
if (cur_a == cur_b) return cur_a;
cur_a = cur_a->next;
cur_b = cur_b->next;
}
return NULL;
}
};
142.环形链表II
思路:快慢指针
-
快慢指针相遇→链表有环
-
为什么快指针一定可以遇到慢指针?
入环之后相当于快指针以一个节点的速度追慢指针 -
推导:
设slow指针一次走一个节点,fast一次走两个节点,n为fast遇到slow时在环中所走的圈数,则有相遇时:
2(x+y) = x+y +n(y+z)
→x = (n-1)(y+z) + z
→x = z
,即x的距离等于z的距离
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 (slow == fast) {
ListNode *tox = head;
ListNode *toz = fast;
while (tox != toz) {
tox = tox->next;
toz = toz->next;
}
return toz;
}
}
return NULL;
}
};