1.反转整个链表
ListNode* reverseBetween(ListNode* head, int m, int n) { if (m == n || head == NULL || head->next == NULL) return head; ListNode* pre = NULL; ListNode* cur = head; int index = 0; while (cur != NULL) { ListNode* tmp = cur->next; cur->next = pre; pre = cur; cur = tmp; } return pre; }
题解 前后指针
前后指针:利用前置指针(其实是个空指针),一个当前指针,步骤如下
初始化pre指针和cur,pre为空指针,cur指向head
1. pre cur
NA 1----> 2---->3---->4---->5
进入到while循环后,利用个临时的tmp指针指向cur的next(因为在一个循环后,需要cur前进一步)
断开cur指针的next,让cur的next指向pre,在第一步的时候cur(也就是链表的head)会指向空,充当新链表的最后一个
然后让pre指针和cur指针各自前进一步
pre = cur
cur = tmp,也就是原先cur的next
2 pre cur
NA<----1 2---->3---->4---->5
还是先用tmp保存cur(2)的next,再断开cur(2)的next,让cur(2)的next指向pre(1)
进而pre和cur再次前进一步
3. pre cur
NA<----1<------2 3---->4---->5
一直到最后,pre最后指向原链表的最后一个,pre的next指向原链表最后一个的前一个
4 5 6... pre cur
NA<----1<------2<------3<------4<------5
2.反转链表的前M个
题解:
1 ListNode* reverseBetween(ListNode* head, int m, int n) { 2 if (m == n || head == NULL || head->next == NULL) 3 return head; 4 5 ListNode* pre = NULL; 6 ListNode* cur = head; 7 ListNode* preS = cur; 8 int index = 0; 9 while (index++ < m) 10 { 11 ListNode* tmp = cur->next; 12 cur->next = pre; 13 pre = cur; 14 cur = tmp; 15 } 16 preS->next = cur; 17 18 return pre; 19 20 }
与反转整个链表不同的是,不能让反转后的最后一个的next是空,
也就是说上面的做法里,原链表的head的next要指向原链表的M+1,
所以需要先用个临时的preS(其实可以直接用入参的head)保存原链表head的地址
在入参是 {1 2 3 4 5} m = 2的情况下
程序运行到第16行时。
pres.val = 1, next = NULL,
cur = {3 4 5}
pre = {2 1}
因为上面已经将pres指向了原链表的head,也就是这个时候pre的尾巴,和pres是同一个节点,地址啥的都是一样,
把pres->next指向cur的head,就能把pre和cur给连起来了
3.反转链表的M到N个(1 ≤ m ≤ n ≤ 链表长度)
输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL
1 //假定head为 1 2 3 4 5, m为2,n为4 2 if (m == n || head == NULL || head->next == NULL) 3 return head; 4 5 //为了适配M为1的情况,设定定个-1节点,-1节点的next为原链表的head 6 ListNode* first = new ListNode(-1); 7 first->next = head; 8 ListNode* preH = first;//preH作为锚(返回值),指向原链表的head, 9 10 int index = 1; 11 while (index++ < m) { 12 first = first->next; 13 } 14 //ListNode* preM = first; 15 16 ListNode* pre = NULL;//相对准备反转的一部分链表,pre为-1节点,循环结束后,为反转后的小段链表的head 17 ListNode* cur = first->next;//cur为第一个要反转的节点,循环结束后,为原链表的后部分的head 18 //依然使用PreS作为第一个反转的锚,当下面的循环结束后,preS也是要反转部分链表的的最后一个节点 19 ListNode* preS = cur; 20 21 while (index++ <= n + 1) 22 { 23 ListNode* tmp = cur->next; 24 cur->next = pre; 25 pre = cur; 26 cur = tmp; 27 } 28 first->next = pre; 29 preS->next = cur; 30 31 return preH->next;
题解:
1.当程序运行到19行后,如下
pre依然是个空,
first指向准备m-1的位置,如果m为1的情况,first为-1节点
first指向m的位置
pre first cur()
preS
NA 1----> 2---->3---->4---->5
2.运行第一遍循环后
节点2和节点3的连接将会断开
pre指向节点2
cur指向节点3 4 5
first不变,指向1,因为2的节点端看,所以first只有 1 2
first pre cur()
preS
NA 1----> 2 3---->4---->5
3. 运行第二遍循环后
pre:3 2
cur:4 5
first:1 2
first pre cur()
preS
NA 1----> 2<----3 4---->5
4.运行第三遍循环后
pre:4 3 2
cur:5
first:1 2
first pre cur()
preS
NA 1----> 2<----3<----4 5
至此,已经将2到4的节点反转了,得到临时链表pre,剩余链表cur
接着把first,pre和cur给连接起来就行
first是原链表节点m-1的位置,而反转从m开始,所以first的next为pre和head
再取pre的tail,在上面已经将原链表2的赋给了preS,所以这个preS和pre的tail为同一个
所以,将preS的next和cur连接起来即可
1 first->next = pre; 2 preS->next = cur;
4.K 个一组翻转链表程序
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
1 ListNode* reverseStart2End(ListNode* head, ListNode* tail) { 2 3 ListNode* pre = NULL; 4 ListNode*cur = head; 5 ListNode* nextNode = tail->next; 6 7 while (cur != nextNode) { 8 ListNode* tmp = cur->next; 9 cur->next = pre; 10 pre = cur; 11 cur = tmp; 12 } 13 head->next = nextNode; 14 return pre; 15 16 } 17 18 ListNode* reverseKGroup1(ListNode* head, int k) { 19 if (k <= 1) return head; 20 21 ListNode* pre = new ListNode(-1); 22 23 //反转部分的头和尾巴 24 ListNode* start = head; 25 ListNode* end = head; 26 ListNode* ex_tail = pre;//记录反转开始的前一个 27 pre->next = head; 28 ListNode*cur = head; 29 int index = 1; 30 31 32 while (end != NULL){ 33 if (index % k == 0){ 34 ListNode* newS = reverseStart2End(start, end); 35 ex_tail->next = end; 36 ex_tail = start; 37 start = start->next; 38 end = start; 39 index = 1; 40 } 41 else{ 42 end = end->next; 43 index++; 44 } 45 } 46 47 return pre->next; 48 }
题解:
reverseStart2End函数是反转从start到end的节点,效果如下:
初始状态和结束结束状态如下:
1.初始化
设定-1节点,next为原链表的head。
设定start和end节点,分别表示要准备反转的head和tail。
设定ex_tial节点,表示start的前一个节点
设定index从1开始
while循环一直判定到end不为NULL
当index%k == 0时,进入反转,定义K=1 head= 1 2 3 4 5 6 7
1st:
在经过reverseStart2End后变得如下:
在这操作之前记录了ex_tail在这个时候就起作用了,因为ex_tail是要反转子链表的前一个,所以
在子链表反转后,需要将ex_tail的next重新指向反转后的子链表的head,也就是在反转前的end(3);
再重新定位ex_tail的位置,从反转链表上来看新的ex_tail也就是反转前的head(1);
so:
1 ex_tail->next = end; 2 ex_tail = start;
接着重新定位start和end位置和初始化index
1 start = start->next; 2 end = start; 3 index = 1;
如此:
2nd:
以下进入2nd反转的姿态
在反转后:
同样需要把ex_tail的next重新连接到反转后子链表的head,也就是反转前的end(6)
重新定位ex_tail的位置,也就是反转前的start(4)
接着重新定位start和end
欧克,这个时候已经没办法满足index % k == 0了,退出while
很明显,可以看出,输出pre->next
打完收工!!!
LeetCode的反转链表
206. 反转链表 反转一个单链表。
92. 反转链表 II 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
25. K 个一组翻转链表 每 k 个节点一组进行翻转