zoukankan      html  css  js  c++  java
  • 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 个一组翻转链表 每 个节点一组进行翻转

     

       

      

  • 相关阅读:
    OC面向对象—继承
    OC面向对象—封装
    OC内存管理
    OC方法和文件编译
    OC语言基础知识
    节点操作-2
    留言 节点操作案例
    js 下拉菜单案例
    节点操作
    tab栏切换效果
  • 原文地址:https://www.cnblogs.com/gongkiro/p/13692508.html
Copyright © 2011-2022 走看看