/**
* 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* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
ListNode* nxt = new ListNode(0);
while(cur != nullptr){
nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
};
/**
* 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* reverseBetween(ListNode* head, int left, int right) {
if(head->next == nullptr){
return head;
}
ListNode* p0 = head;
for(int i =1;i<left-1;i++){
p0 = p0->next;
}
ListNode* cur = p0->next;
ListNode* pre = new ListNode(0);
ListNode* nxt = new ListNode(0);
int times = right - left + 1;
for(int i =0;i<times;i++){
nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
p0->next->next = cur;
p0->next = pre;
return 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* reverseKGroup(ListNode* head, int k) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* fast = head;
int num = 0;
while(fast){
fast = fast->next;
num++;
}
ListNode* p0 = dummy;
while( num-k >= 0){
num -= k;
ListNode* cur = p0->next;
ListNode* pre = nullptr;
ListNode* nxt = nullptr;
for(int i = 0;i<k;i++){
nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
nxt = p0->next;
p0->next->next = cur;
p0->next = pre;
p0 = nxt;
}
return dummy->next;
}
};
今天是我第二次写这三道题,昨天跟朋友一起讨论408历年真题的算法设计题,里面有一个涉及到快慢指针找中点,然后反转后半段链表的。我就重新做了一下这三道反转链表题。并且有了更进一步的理解。
首先最核心的代码就是这四句:
nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
然后这个pre和nxt都是可以初始化成一个空指针的。cur就是你要反转的第一个结点。
这四句的意思把cur反转指向pre。最后再让两个指针向右移动。
1.如果是反转全部链表,就只需要判断cur为空的时候停止反转就可以了,最后返回pre
2.如果是反转区间链表,就需要一个p0指示cur,让cur = p0->next;这个p0我的理解就是为反转区间结点善后的。当你反转好一个区间的链表,还要执行下面这2句:
p0->next->next = cur;
p0->next = pre;
就是让区间左边界内的第一个节点指向区间右边界外面的第一个节点,再让p0指向pre,就是区间右边界内的第一个节点。
这是示意图:
3.如果是k个一组反转链表,这时候这个指示器p0作用就更大了,它就要指示多个区间。
在K个一组节点基本的反转结束后要执行这4句话:
nxt = p0->next;
p0->next->next = cur;
p0->next = pre;
p0 = nxt;
这里要非常非常注意的地方是先保存p0->next,因为反转链表以后这K个节点组成的区间内第一个节点就变成了最后一个节点,然后下一次的p0是要移动到这个区间的最后一个节点,也就是下一个区间前的第一个节点。所以一定一定要保存p0->next为nxt,最后把p0移动到nxt。这是它与第二问区间反转最大的不同。其他地方都差求不多。
个人感觉我的图画的也是比较清楚了。我想这里有个细节可能大家也注意到了,就是在区间反转的时候,cur总是会“探出”这个区间,指到下一个区间的第一个节点。这个性质也要活用呦。
如果是408那道题,从中点反转链表,我们只需要用最简单的第一问的方法,从中点后面全部反转即可。希望看完这篇文章能对你学习反转链表有所帮助~
博主是算法小菜鸟,大家一起进步~