LeetCode 反转链表

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 个一组翻转链表 每 个节点一组进行翻转

 

 

 

 

 

 

 

 

 

 

 

 

   

 

 

 

  

 

posted @ 2020-09-18 17:40  GongKiro  阅读(357)  评论(0编辑  收藏  举报