![57dc8cbf14c916fb73f6ed251a9b0d52.png](https://i-blog.csdnimg.cn/blog_migrate/5623c07b5aee0bba66434b8b428d8f62.jpeg)
在面对leetcode上链表相关问题时,有一些注意点:
- 交换链表节点时,我们可以先记录下
prev cur next
节点指针。当遍历到cur
节点时,记录前后两个节点,在遍历过程中修改prev cur next
达到交换节点的效果。 - 最先定义一个虚拟节点
dummy->next = head
起到固定的作用。如果头节点也移动了,则直接通过这个虚拟节点返回。 - 判断链表有环: 快(2步)慢(1步)指针相遇,相遇后从相遇点和起点同时出发(速度1步),再次相遇为环位置。
- 两个链表A和B判断是否相交, A+B B+A后长度相同。从头节点开始遍历,当节点next为nullptr时再指向另一个链表头节点,之后遍历相遇时就可以判断相交。
接下来做一道非常经典的链表题目: 25. K 个一组翻转链表
![64ae16c3b77d031b4815e822cc25bcbc.png](https://i-blog.csdnimg.cn/blog_migrate/7188699b36a339045c1dbb9f36b3b817.png)
- 考虑用
prev head tail
三个指针去记录k个一组子链表的首(head
)尾(tail
)节点,prev
为head
的前一个节点,因为head tail
都反转了,需要用prev
去维系前面子链表和当前反转子链表的关系。 - 定义个函数,输入
head tail
,经过翻转后返回新的head tail
- 担心第一个节点就要会被移动,所以先定义一个虚节点
dummy
,放在链表首节点前。dummy->next = head
接下来上代码:
class Solution {
public:
// 反转head到tail这一段的链表,并返回反转后的首尾节点 head tail
pair<ListNode*, ListNode*> reverseHeadAndTail(ListNode* head, ListNode* tail) {
ListNode* prev = tail->next, * cur = head;
while (prev != tail) { // 每次都改变prev和cur的next指向,之后向后遍历
ListNode* next = cur->next;
cur->next = prev; // 每次只改cur的next指针指向
prev = cur;
cur = next;
}
return {tail, head};
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy = new ListNode(-1); // head可能会移动,所以设置一个虚节点
dummy->next = head;
ListNode* prev = dummy;
while (head) {
ListNode* tail = prev;
// head tail 即为需要翻转的子链表
for (int i = 0; i < k; i++) {
tail = tail->next;
if (tail == nullptr) return dummy->next;
}
ListNode* next = tail->next;
pair<ListNode*, ListNode*> res = reverseHeadAndTail(head, tail);
head = res.first;
tail = res.second;
prev->next = head;
tail->next = next;
prev = tail;
head = next;
}
return dummy->next;
}
};