一、题目
25. K 个一组翻转链表
206. 反转链表
92. 反转链表 II
二、分析
这个看似很难,但是化繁为简之后,一切就“拨开云雾见天日”了,但是写代码仍然要非常细心。
- 拆分成子问题:给定一个头尾指针,翻转整个链表,就成了题目中2、3题。
- 每隔k步,进行一次上述操作。
三、代码
class Solution {
public:
// 辅助函数,翻转部分链表(给定头尾指针)
pair<ListNode *, ListNode *> reverseOne(ListNode *head, ListNode *tail){
tail->next = nullptr;
ListNode* pleft = head;
ListNode* pright = head->next;
while(pright != nullptr){
ListNode* temp = pright->next;
pright->next = pleft;
pleft = pright;
pright = temp;
}
// head->next 还是原来的第二个节点
return make_pair(pleft,head);
}
ListNode* reverseKGroup(ListNode* head, int k) {
if(k <= 1) return head;
int count(0);
ListNode * dumpy = new ListNode();
dumpy->next = head;
ListNode * p = head;
ListNode * pfixLeft = dumpy;
while(p != nullptr){
count++;
if(count % k == 0){ //关键操作,建议画图理解一下
ListNode * temp = p->next;
pair<ListNode *, ListNode *> res = reverseOne(pfixLeft->next, p);
pfixLeft->next = res.first;
pfixLeft = res.second;
pfixLeft->next = temp;
p = temp;
continue;
}
p = p->next;
}
return dumpy->next;
}
};
执行用时:16 ms, 在所有 C++ 提交中击败了90.73%的用户
内存消耗:11.2 MB, 在所有 C++ 提交中击败了52.97%的用户
class Solution {
public:
ListNode* reverseList(ListNode* head){
if(head == nullptr || head->next == nullptr) return head;
ListNode* pleft = head;
ListNode* pright = head->next;
while(pright != nullptr){
ListNode* temp = pright->next;
pright->next = pleft;
pleft = pright;
pright = temp;
}
head->next = nullptr;
return pleft;
}
};
执行用时:8 ms, 在所有 C++ 提交中击败了68.84%的用户
内存消耗:8.1 MB, 在所有 C++ 提交中击败了53.23%的用户
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
if(left == right) return head;
ListNode *fakerhead = new ListNode();
ListNode *fakertail = new ListNode();
fakerhead->next = head;
ListNode * pright = fakerhead;
ListNode * pleft = fakerhead;
int i(0);
bool flag = false;
// 找到 pleft 和 pright
while(pright != nullptr){
if(i == left - 1){
pleft = pright;
}else if(i == right){
break;
}
pright = pright->next;
i++;
}
// 考虑pright是 tail节点的特殊情况
if(pright->next == nullptr){
flag = true;
pright->next = fakertail;
}
pright = pright->next;
i = 0;
//开始真正的翻转部分链表,给定头尾指针(和25题的做法不太一样)
ListNode * p = pleft->next;
ListNode * temp = p->next;
while(i < right - left + 1){
p->next = pright;
pright = p;
if(i == right- left) break;
p = temp;
temp = temp->next;
i++;
}
pleft->next = p;
//仍然是考虑pright是tail节点的情况
if(flag){
p = fakerhead->next;
while(p!= nullptr){
if(p->next->next == nullptr) p->next = nullptr;
p = p->next;
}
}
return fakerhead->next;
}
};
执行用时:16 ms, 在所有 C++ 提交中击败了100%的用户
内存消耗:7.3 MB, 在所有 C++ 提交中击败了32.97%的用户