题目描述:给你一个链表,两两交换其中相邻的节点,返回交换后链表的头节点
视频讲解https://www.bilibili.com/video/BV1YT411g7br/?vd_source=f98f2942b3c4cafea8907a325fc56a48文章讲解
https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html#_24-%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9
笔记整理:
- 思路:
- 欲交换相邻节点1和2,就要知道1之前的节点(为统一操作,使用虚拟头节点)
- 将链表划分为:已交换部分、未交换部分考虑
- 起始:已交换部分为dummyHead
- 终止:未交换部分为 nullptr 或 只剩一个节点
- 每次交换操作前,cur定位到未交换部分首位,tmp定位到cur的后继
- 交换cur和tmp,具体步骤:
![](https://img-blog.csdnimg.cn/f443791ab24d4237a61cba96c8356316.png)
![](https://img-blog.csdnimg.cn/057a7bb3a94c4260a40d2d439ad21d18.png)
![](https://img-blog.csdnimg.cn/45d47ba8a0ac431c8ec6518dedc4bda9.png)
![](https://img-blog.csdnimg.cn/0e3c7b557b234fdb83ffc798ded2853c.png)
- 代码:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
// 虚拟头节点
ListNode* dummyHead = new ListNode(0, head);
// 已交换部分的尾节点
ListNode* pre = dummyHead;
// 待交换部分的头节点
ListNode* cur = dummyHead;
while (cur->next != nullptr) {
cur = cur->next;
ListNode* tmp = cur->next;
// 只剩一个节点
if (tmp == nullptr) {
break;
}
// 交换cur和tmp
cur->next = tmp->next;
tmp->next = cur;
pre->next = tmp;
// 交换完成,更新已交换部分的尾节点
pre = cur;
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
题目描述:给你一个链表,删除链表的倒数第 n
个节点,并且返回链表的头节点
- 删除倒数第n个节点,需要定位到倒数第n个节点的前一个(倒数第n+1)
视频讲解https://www.bilibili.com/video/BV1vW4y1U7Gf/?vd_source=f98f2942b3c4cafea8907a325fc56a48文章讲解
https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html笔记整理:
- 思路:
- 双指针:快指针先走n步,后快慢指针一起移动
- 快指针到尾节点(倒数第1),慢指针恰好到达待删节点前一个(倒数第n+1)
- 代码:
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
// 删除倒数第n个节点,需要定位到其前驱
// fast先走n步,fast走到尾节点时,slow走到倒数第n个节点的前驱
// 设置虚拟头节点,方便操作n == sz的情况
ListNode* dummyHead = new ListNode(0, head);
ListNode* fast = dummyHead;
ListNode* slow = dummyHead;
while (n--) {
fast = fast->next;
}
while (fast->next != nullptr) {
fast = fast->next;
slow = slow->next;
}
// 删除slow->next
ListNode* tmp = slow->next;
slow->next = slow->next->next;
delete tmp;
head = dummyHead->next;
delete dummyHead;
return head;
}
};
题目描述:给定两个单链表的头节点 headA 和 headB ,找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。不允许修改 链表!
- 思路:
- LeetCode 160:
- 双指针:分别从A、B头节点出发,在交点相遇,考虑此过程可以利用的信息
- A的长度?B的长度?A+B的长度√
- 若存在交点,pre先遍历链表A,再遍历链表B,cur先B后A,两指针将于交点相遇
- 对于没有交点的情况,pre先A后B,cur先B后A,会同时到达 nullptr (若A与B长度相等,pre遍历完A,cur遍历完B,即同时到达 nullptr)
- 双指针:分别从A、B头节点出发,在交点相遇,考虑此过程可以利用的信息
- 代码随想录:
- 分别求出链表A长度、链表B长度、长度差x
- 令curA从长链表头节点出发,先走x步
- 令curB从短链表头节点出发,同时移动curA
- 若存在交点,curA和curB必在交点相遇
- 若不存在交点,curA和curB也会同时走到nullptr
- LeetCode 160:
- 代码:
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* pre = headA;
ListNode* cur = headB;
while (pre != cur) {
if (pre == nullptr) {
pre = headB;
} else {
pre = pre->next;
}
if (cur == nullptr) {
cur = headA;
} else {
cur = cur->next;
}
}
return pre;
}
};
// 代码随想录
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
题目描述:给定一个链表的头节点,返回链表开始入环的第一个节点。(无环返回 null)
视频讲解https://www.bilibili.com/video/BV1if4y1d7ob/?vd_source=f98f2942b3c4cafea8907a325fc56a48文章讲解
https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
笔记整理:
- 思路:
- 快指针一次走两步,慢指针一次走一步
- 有环:慢指针入环,快指针一步一步追上慢指针,一定会在环里相遇
- 无环:快指针先走到 尾节点 或 nullptr
- 找入环点:
- 不妨设入环点在x处,环长为l,考虑两个时刻(如图)
- pre从头节点出发,cur从相遇点出发,均一次走一步,将在入环点相遇
![](https://img-blog.csdnimg.cn/4b5bf00dd1b249fcba0175345c214c13.png)
fast已在环内走了x步
可知:x == n * l + (l - p)
![](https://img-blog.csdnimg.cn/3e47902f583343eeb8073450e2f775b5.png)
可知:从相遇点再走(l - p)步即为入环点
- 代码:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
// fast一次走两步,slow一次走一步
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next;
slow = slow->next;
// 快慢指针相遇,说明有环
if (fast == slow) {
ListNode* pre = head;
ListNode* cur = fast;
while (pre != cur) {
pre = pre->next;
cur = cur->next;
}
// 在入环点相遇
return cur;
}
}
// 链表无环
return nullptr;
}
};