zoukankan      html  css  js  c++  java
  • 链表问题集锦

      链表节点的结构:

    struct ListNode {
        int val;
        ListNode* next;
        ListNode(int _val = -1)
        {
            val = _val;
            next = nullptr;
        }
    };

    一、在O(1)时间删除链表节点

    题目描述:给定链表的头指针和一个节点指针,在O(1)时间删除该节点。[Google面试题]

    分析:本题与《编程之美》上的「从无头单链表中删除节点」类似。主要思想都是「狸猫换太子」,即用下一个节点数据覆盖要删除的节点,然后删除下一个节点。但是如果节点是尾节点时,该方法就行不通了。

    代码:如下

    1 void DeleteRandomNode(ListNode* cur)
    2 {
    3     assert(cur == nullptr);        //不能是空节点
    4     assert(cur->next == nullptr);    //不能是尾节点
    5     ListNode* pnext = cur->next;
    6     cur->val = pnext->val;
    7     cur->next = pnext->next;
    8 }

    二、求链表倒数第k个节点

    题目描述:输入一个单向链表,输出该链表中倒数第k个节点,链表的倒数第0个节点为链表的尾指针。

    分析:设置两个指针 p1、p2,首先 p1 和 p2 都指向 head,然后 p2 向前走 k 步,这样 p1 和 p2 之间就间隔 k 个节点,最后 p1 和 p2 同时向前移动,直至 p2 走到链表末尾。

    代码:如下

     1 ListNode* TheKthListNode(ListNode* head, int k)
     2 {
     3     ListNode* node = head;
     4     while (k)
     5     {
     6         node = node->next;
     7         k--;
     8     }
     9     while (node)
    10     {
    11         node = node->next;
    12         head = head->next;
    13     }
    14     return head;
    15 }

    三、求链表中间节点

    题目描述:求链表的中间节点,如果链表的长度为偶数,返回中间两个节点的任意一个,若为奇数,则返回中间节点。

    分析:此题的解决思路和第3题「求链表的倒数第 k 个节点」很相似。可以先求链表的长度,然后计算出中间节点所在链表顺序的位置。但是如果要求只能扫描一遍链表,如何解决呢?最高效的解法和第3题一样,通过两个指针来完成。用两个指针从链表头节点开始,一个指针每次向后移动两步,一个每次移动一步,直到快指针移到到尾节点,那么慢指针即是所求。

    代码:如下

     1 ListNode* TheMidListNode(ListNode* head)
     2 {
     3     ListNode* slow = head;
     4     ListNode* fast = head;
     5 
     6     while (fast && fast->next)
     7     {
     8         slow = slow->next;
     9         fast = fast->next->next;
    10     }
    11     
    12     return slow;
    13 }

    四、判断单链表是否存在环

    题目描述:输入一个单向链表,判断链表是否有环?

    分析:通过两个指针,分别从链表的头节点出发,一个每次向后移动一步,另一个移动两步,两个指针移动速度不一样,如果存在环,那么两个指针一定会在环里相遇。

    代码:如下

     1 bool HasCircle(ListNode* &head)
     2 {
     3     if (head == nullptr || head->next == nullptr)
     4         return false;
     5 
     6     ListNode* slow = head;
     7     ListNode* fast = head;
     8 
     9     while (fast && fast->next)
    10     {
    11         fast = fast->next->next;
    12         slow = slow->next;
    13         if (slow == fast)
    14             return true;
    15     }
    16     return false;
    17 }

    五、找到环的入口点

    题目描述:输入一个单向链表,判断链表是否有环。如果链表存在环,如何找到环的入口点?

    分析:由上题可知,按照 p2 每次两步,p1 每次一步的方式走,发现 p2 和 p1 重合,确定了单向链表有环路了。接下来,让p2回到链表的头部,重新走,每次步长不是走2了,而是走1,那么当 p1 和 p2 再次相遇的时候,就是环路的入口了。

    为什么:假定起点到环入口点的距离为 a,p1 和 p2 的相交点M与环入口点的距离为b,环路的周长为L,当 p1 和 p2 第一次相遇的时候,假定 p1 走了 n 步。那么有:p1走的路径: a+b = n;p2走的路径: a+b+k*L = 2*n; p2 比 p1 多走了k圈环路,总路程是p1的2倍

    根据上述公式可以得到 k*L=a+b=n显然,如果从相遇点M开始,p1 再走 n 步的话,还可以再回到相遇点,同时p2从头开始走的话,经过n步,也会达到相遇点M。

    显然在这个步骤当中 p1 和 p2 只有前 a 步走的路径不同,所以当 p1 和 p2 再次重合的时候,必然是在链表的环路入口点上。

    代码:如下

     1 ListNode* FindLoopPort(ListNode* head)
     2 {
     3     if (head == nullptr || head->next == nullptr)
     4         return nullptr;
     5 
     6     ListNode* slow = head;
     7     ListNode* fast = head;
     8 
     9     while (fast && fast->next)
    10     {
    11         fast = fast->next->next;
    12         slow = slow->next;
    13         if (slow == fast)
    14             break;
    15     }
    16 
    17     if (slow != fast)
    18         return nullptr;
    19 
    20     fast = head;
    21 
    22     while (fast != slow)
    23     {
    24         fast = fast->next;
    25         slow = slow->next;
    26     }
    27 
    28     return slow;
    29 }

    六、判断两个链表是否相交

    题目描述:给出两个单向链表的头指针(如下图所示),判断这两个链表是否相交。这里为了简化问题,我们假设两个链表均不带环。

    分析

      1、直接循环判断第一个链表的每个节点是否在第二个链表中。但,这种方法的时间复杂度为O(Length(h1) * Length(h2))。显然,我们得找到一种更为有效的方法,至少不能是O(N^2)的复杂度。

      2、针对第一个链表直接构造hash表,然后查询hash表,判断第二个链表的每个节点是否在hash表出现,如果所有的第二个链表的节点都能在hash表中找到,即说明第二个链表与第一个链表有相同的节点。时间复杂度为为线性:O(Length(h1) + Length(h2)),同时为了存储第一个链表的所有节点,空间复杂度为O(Length(h1))。是否还有更好的方法呢,既能够以线性时间复杂度解决问题,又能减少存储空间?

      3、转换为环的问题。把第二个链表接在第一个链表后面,如果得到的链表有环,则说明两个链表相交。如何判断有环的问题上面已经讨论过了,但这里有更简单的方法。因为如果有环,则第二个链表的表头一定也在环上,即第二个链表会构成一个循环链表,我们只需要遍历第二个链表,看是否会回到起始点就可以判断出来。这个方法的时间复杂度是线性的,空间是常熟。

      4、进一步考虑“如果两个没有环的链表相交于某一节点,那么在这个节点之后的所有节点都是两个链表共有的”这个特点,我们可以知道,如果它们相交,则最后一个节点一定是共有的。而我们很容易能得到链表的最后一个节点,所以这成了我们简化解法的一个主要突破口。那么,我们只要判断两个链表的尾指针是否相等。相等,则链表相交;否则,链表不相交。

    所以,先遍历第一个链表,记住最后一个节点。然后遍历第二个链表,到最后一个节点时和第一个链表的最后一个节点做比较,如果相同,则相交,否则,不相交。这样我们就得到了一个时间复杂度,它为O((Length(h1) + Length(h2)),而且只用了一个额外的指针来存储最后一个节点。这个方法时间复杂度为线性O(N),空间复杂度为O(1),显然比解法三更胜一筹。

    代码:如下

     1 ListNode* IsIntersect(ListNode* head1, ListNode* head2)
     2 {
     3     ListNode* node1 = head1;
     4     ListNode* node2 = head2;
     5 
     6     while (node1 != node2)
     7     {
     8         node1 = node1 == nullptr ? head2 : node1->next;
     9         node2 = node2 == nullptr ? head1 : node2->next;
    10     }
    11 
    12     return node1;
    13 }

    七、两个链表相交的第一个公共节点

    题目描述:如果两个无环单链表相交,怎么求出他们相交的第一个节点呢?

    分析:采用对齐的思想。计算两个链表的长度 L1 , L2,分别用两个指针 p1 , p2 指向两个链表的头,然后将较长链表的 p1(假设为 p1)向后移动L2 - L1个节点,然后再同时向后移动p1 , p2,直到 p1 = p2。相遇的点就是相交的第一个节点。

    代码:如下

     1 ListNode* FindIntersectListNode(ListNode* head1, ListNode* head2)
     2 {
     3     ListNode* node1 = head1;
     4     ListNode* node2 = head2;
     5 
     6     
     7     int len1 = 0, len2 = 0;
     8     while (node1)
     9     {
    10         node1 = node1->next;
    11         len1++;
    12     }
    13     while (node2)
    14     {
    15         node2 = node2->next;
    16         len2++;
    17     }
    18 
    19     node1 = head1;
    20     node2 = head2;
    21     if (len1 > len2)
    22     {
    23         while (len1 > len2)
    24         {
    25             node1 = node1->next;
    26             len1--;
    27         }
    28     }
    29     else
    30     {
    31         while (len2 > len1)
    32         {
    33             node2 = node2->next;
    34             len2--;
    35         }
    36     }
    37 
    38     while (node1 != node2)
    39     {
    40         node1 = node1->next;
    41         node2 = node2->next;
    42     }
    43 
    44     return node1;
    45 }

    八、链表有环,如何判断相交

    题目描述:上面的问题都是针对链表无环的,那么如果现在,链表是有环的呢?上面的方法还同样有效么?

    分析:如果有环且两个链表相交,则两个链表都有共同一个环,即环上的任意一个节点都存在于两个链表上。因此,就可以判断一链表上俩指针相遇的那个节点,在不在另一条链表上。

    代码:如下

     1 bool HasCircle(ListNode* head, ListNode* &node)
     2 {
     3     node = nullptr;
     4     if (head == nullptr || head->next == nullptr)
     5         return false;
     6 
     7     ListNode* slow = head;
     8     ListNode* fast = head;
     9 
    10     while (fast && fast->next)
    11     {
    12         fast = fast->next->next;
    13         slow = slow->next;
    14         if (slow == fast)
    15         {
    16             node = slow;
    17             return true;
    18         }
    19     }
    20 
    21     return false;
    22 }
    23 
    24 
    25 bool IsIntersectWithLoop(ListNode* head1, ListNode* head2)
    26 {
    27     ListNode* CircleNode1 = nullptr, *CircleNode2 = nullptr;
    28     if (!HasCircle(head1, CircleNode1))
    29         return false;
    30     if (!HasCircle(head2, CircleNode2))
    31         return false;
    32 
    33     ListNode* temp = CircleNode2->next;
    34     while (temp != CircleNode2)
    35     {
    36         if (temp == CircleNode1)
    37             return true;
    38         temp = temp->next;
    39     }
    40     return false;
    41 }

    九、两个可能有环链表相交找交点

    第一种情况:两个链表都有环且不相交

    第二种情况:两个链表都有环且不相交两个链表都有环相交,交点不在环上,或正好在入口点

    第三种情况:两个链表都有环且不相交两个链表都有环相交,交点在环上

    第二种情况和无环相交类似,只是快节点走到null改为快节点走到环入口点
    第三种情况,第一种情况 --> 找到两个链表的入口点,让一个链表的节点继续走,如果走一圈又走回来了没有碰到另一个入口点说明为情况1,若遇到了说明为情况2。

    解决:

      1 ListNode* FindLoopPort(ListNode* head)
      2 {
      3     if (head == nullptr || head->next == nullptr)
      4         return nullptr;
      5 
      6     ListNode* slow = head;
      7     ListNode* fast = head;
      8 
      9     while (fast && fast->next)
     10     {
     11         fast = fast->next->next;
     12         slow = slow->next;
     13         if (slow == fast)
     14             break;
     15     }
     16 
     17     if (slow != fast)
     18         return nullptr;
     19 
     20     fast = head;
     21 
     22     while (fast != slow)
     23     {
     24         fast = fast->next;
     25         slow = slow->next;
     26     }
     27 
     28     return slow;
     29 }
     30 
     31 
     32 ListNode* FindIntersectWithLoopListNode(ListNode* head1, ListNode* head2)
     33 {
     34     if (head1 == nullptr || head2 == nullptr)
     35         return nullptr;
     36 
     37     ListNode* loop1 = FindLoopPort(head1);
     38     ListNode* loop2 = FindLoopPort(head2);
     39     
     40 
     41     if (loop1 == nullptr || loop2 == nullptr) //必有一个无环
     42     {
     43         return nullptr;
     44     }
     45 
     46     if (loop1 == loop2)
     47     {
     48         int len1 = 0;
     49         ListNode* node1 = head1;
     50         while (node1)
     51         {
     52             len1++;
     53             node1 = node1->next;
     54         }
     55 
     56         int len2 = 0;
     57         ListNode* node2 = head2;
     58         while (node2)
     59         {
     60             len2++;
     61             node2 = node2->next;
     62         }
     63 
     64         node1 = head1;
     65         node2 = head2;
     66 
     67         if (len1 > len2)
     68         {
     69 
     70             while (len1 > len2)
     71             {
     72                 node1 = node1->next;
     73                 len1--;
     74             }
     75         }
     76         else
     77         {
     78             while (len2 > len1)
     79             {
     80                 node2 = node2->next;
     81                 len2--;
     82             }
     83         }
     84 
     85         while (node1 != node2)
     86         {
     87             node1 = node1->next;
     88             node2 = node2->next;
     89         }
     90     }
     91     else
     92     {
     93         ListNode* node = loop1->next;
     94         while (node != loop1)
     95         {
     96             if (node == loop2)
     97                 return node;
     98             node = node->next;
     99         }
    100         return nullptr;
    101     }
    102     
    103     return nullptr;
    104 }

    十、单链表的反转

    题目描述:输入一个单向链表,输出逆序反转后的链表

    分析:链表的转置是一个很常见、很基础的数据结构题了,非递归的算法很简单,用三个临时指针 pre、head、next 在链表上循环一遍即可。递归算法也是比较简单的,但是如果思路不清晰估计一时半会儿也写不出来吧。

    代码:如下

     1 ListNode* ReverseList(ListNode* head)
     2 {
     3     if (head == nullptr || head->next == nullptr)
     4         return head;
     5 
     6     ListNode* vhead = new ListNode(-1);
     7 
     8     while (head)
     9     {
    10         ListNode* node = head->next;
    11         head->next = vhead->next;
    12         vhead->next = head;
    13         head = node;
    14     }
    15     return vhead->next;
    16 }

    递归写法:

     1 ListNode* ReverseList(ListNode* head)
     2 {
     3     if (head == nullptr || head->next == nullptr)
     4         return head;
     5 
     6     ListNode* node = head->next;
     7     ListNode* newhead = ReverseList(head->next);
     8 
     9     node->next = head;
    10     head->next = nullptr;
    11     return newhead;
    12 }

    十一、k个一组进行链表反转

    k个节点为一组进行反转,不足k个的部分不需要反转。

     1 #include <iostream>
     2 #include <vector>
     3 
     4 using namespace std;
     5 
     6 struct ListNode {
     7     int val;
     8     ListNode* next;
     9     ListNode(int _val)
    10     {
    11         val = _val;
    12         next = nullptr;
    13     }
    14 };
    15 
    16 
    17 ListNode* CreateList(vector<int> reg)
    18 {
    19     ListNode* vhead = new ListNode(-1);
    20     ListNode* tail = vhead;
    21 
    22     for (int i = 0; i < reg.size(); i++)
    23     {
    24         ListNode* node = new ListNode(reg[i]);
    25         tail->next = node;
    26         tail = node;
    27     }
    28     return vhead->next;
    29 }
    30 
    31 void PrintList(ListNode* head)
    32 {
    33     while (head)
    34     {
    35         cout << head->val << " ";
    36         head = head->next;
    37     }
    38     cout << endl;
    39 }
    40 
    41 ListNode* ReverseList(ListNode* head, int k)
    42 {
    43     if (head == nullptr || head->next == nullptr || k == 1)
    44         return head;
    45 
    46     int len = 0;
    47 
    48     ListNode* node = head;
    49     while (node)
    50     {
    51         len++;
    52         node = node->next;
    53     }
    54 
    55     int cnt = len / k;
    56 
    57     ListNode* vhead = new ListNode(-1);
    58     ListNode* vtail = vhead;
    59     node = head;
    60     while (cnt)
    61     {
    62         int t = k;
    63         ListNode* thead = new ListNode(-1);
    64         ListNode* end = nullptr;
    65         while (t)
    66         {
    67             if (end == nullptr)
    68                 end = node;
    69             ListNode* temp = node->next;
    70             node->next = thead->next;
    71             thead->next = node;
    72             node = temp;
    73             t--;
    74         }
    75         vtail->next = thead->next;
    76         vtail = end;
    77         cnt--;
    78     }
    79     vtail->next = node;
    80     return vhead->next;
    81 }
    82 
    83 int main()
    84 {
    85     vector<int> reg = { 1,2,3,4,5,6,7 };
    86 
    87     ListNode* head = CreateList(reg);
    88 
    89     PrintList(head);
    90 
    91     ListNode* newhead = ReverseList(head, 3);
    92 
    93     PrintList(newhead);
    94     return 0;
    95 }
    View Code

    十二、指定区域链表反转

    题目描述:给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

    示例1:

    解法一:

      整体思想是:在需要反转的区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置。下面的图展示了整个流程。

      下面我们具体解释如何实现。使用三个指针变量 pre、curr、next 来记录反转的过程中需要的变量,它们的意义如下:

        curr:指向待反转区域的第一个节点 left;
        next:永远指向 curr 的下一个节点,循环过程中,curr 变化以后 next 会变化;
        pre:永远指向待反转区域的第一个节点 left 的前一个节点,在循环过程中不变。
      第 1 步,我们使用 ①、②、③ 标注「穿针引线」的步骤。

      操作步骤:

        先将 curr 的下一个节点记录为 next;
        执行操作 ①:把 curr 的下一个节点指向 next 的下一个节点;
        执行操作 ②:把 next 的下一个节点指向 pre 的下一个节点;
        执行操作 ③:把 pre 的下一个节点指向 next。
      第 1 步完成以后「拉直」的效果如下:

      第 2 步,同理。同样需要注意 「穿针引线」操作的先后顺序。

      第 2 步完成以后「拉直」的效果如下:

      第 3 步,同理。

      第 3 步完成以后「拉直」的效果如下:

      代码如下:

     1 ListNode* reverseBetween(ListNode* head, int left, int right) {
     2     ListNode* vhead = new ListNode(-1);
     3     vhead->next = head;
     4     ListNode* tail = vhead;
     5     int n = left;
     6     while (tail && n > 1)
     7     {
     8         tail = tail->next;
     9         n--;
    10     }
    11 
    12     ListNode* cur = tail->next;
    13     for (int i = 0; i < right - left; i++)
    14     {
    15         ListNode* node = cur->next;
    16 
    17         cur->next = node->next;
    18         node->next = tail->next;
    19         tail->next = node;
    20     }
    21 
    22     return vhead->next;
    23 }

    解法二:

      整体思想就是将氛围三个部分,前面不需要反转的区域,需要反转的区域,后面不需要反转的区域。将需要反转的区域当作一个子串,进行反转,然后再将三部分进行拼接。

    代码如下:

     1 ListNode* ReverseList(ListNode* head)
     2 {
     3     if (head == nullptr || head->next == nullptr)
     4         return head;
     5 
     6     ListNode* vhead = new ListNode(-1);
     7 
     8     while (head)
     9     {
    10         ListNode* node = head->next;
    11         head->next = vhead->next;
    12         vhead->next = head;
    13         head = node;
    14     }
    15     return vhead->next;
    16 }
    17 
    18 ListNode *reverseBetween(ListNode *head, int left, int right) {
    19     // 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
    20     ListNode *vhead = new ListNode(-1);
    21     vhead->next = head;
    22 
    23     ListNode *pre = vhead;
    24     // 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点
    25     // 建议写在 for 循环里,语义清晰
    26     for (int i = 0; i < left - 1; i++) {
    27         pre = pre->next;
    28     }
    29 
    30     // 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
    31     ListNode *rightNode = pre;
    32     for (int i = 0; i < right - left + 1; i++) {
    33         rightNode = rightNode->next;
    34     }
    35 
    36     // 第 3 步:切断出一个子链表(截取链表)
    37     ListNode *leftNode = pre->next;
    38     ListNode *curr = rightNode->next;
    39 
    40     // 注意:切断链接
    41     pre->next = nullptr;
    42     rightNode->next = nullptr;
    43 
    44     // 第 4 步:同第 206 题,反转链表的子区间
    45     leftNode = ReverseList(leftNode);
    46 
    47     // 第 5 步:接回到原来的链表中
    48     pre->next = rightNode;
    49     leftNode->next = curr;
    50     return vhead->next;
    51 }

    十三、链表排序

    解决:

     1 ListNode* MergeList(ListNode* left, ListNode* right)
     2 {
     3     if (left == nullptr)
     4         return right;
     5     if (right == nullptr)
     6         return left;
     7 
     8     if (left->val < right->val)
     9     {
    10         left->next = MergeList(left->next, right);
    11         return left;
    12     }
    13     else
    14     {
    15         right->next = MergeList(left, right->next);
    16         return right;
    17     }
    18 }
    19 
    20 ListNode* FindMidListNode(ListNode* head)
    21 {
    22     ListNode* slow = head;
    23     ListNode* fast = head;
    24 
    25     while (fast && fast->next && fast->next->next)
    26     {
    27         slow = slow->next;
    28         fast = fast->next->next;
    29     }
    30     return slow;
    31 }
    32 
    33 ListNode* sortList(ListNode* head) {
    34     if (head == nullptr || head->next == nullptr)
    35         return head;
    36 
    37     ListNode* mid = FindMidListNode(head);
    38     ListNode* newhead = mid->next;
    39     mid->next = nullptr;
    40 
    41     ListNode* head1 = sortList(head);
    42     ListNode* head2 = sortList(newhead);
    43 
    44     ListNode* thead = MergeList(head1, head2);
    45 
    46     return thead;
    47 }
    View Code

    十四、合并有序链表

    题目链接:

      https://leetcode-cn.com/problems/vvXgSW/

    给定一个链表数组,每个链表都已经按升序排列。

    请将所有链表合并到一个升序链表中,返回合并后的链表。

    实例1:

    输入:lists = [[1,4,5],[1,3,4],[2,6]]
    输出:[1,1,2,3,4,4,5,6]
    解释:链表数组如下:
    [
      1->4->5,
      1->3->4,
      2->6
    ]
    将它们合并到一个有序链表中得到。
    1->1->2->3->4->4->5->6

    解决:

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode() : val(0), next(nullptr) {}
     7  *     ListNode(int x) : val(x), next(nullptr) {}
     8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
     9  * };
    10  */
    11 class Solution {
    12 public:
    13     ListNode* MergeList(ListNode* left, ListNode* right)
    14     {
    15         if (left == nullptr)
    16             return right;
    17         if (right == nullptr)
    18             return left;
    19 
    20         if (left->val < right->val)
    21         {
    22             left->next = MergeList(left->next, right);
    23             return left;
    24         }
    25         else
    26         {
    27             right->next = MergeList(left, right->next);
    28             return right;
    29         }
    30     }
    31 
    32     ListNode* mergeKLists(vector<ListNode*>& lists) {
    33         ListNode* ans = nullptr;
    34         for(int i=0; i<lists.size(); i++)
    35         {
    36             ans = MergeList(ans, lists[i]);
    37         }
    38         return ans;
    39     }
    40 };

    十五、回文链表

    题目链接:

      https://leetcode-cn.com/problems/aMhZSa/

    给定一个链表的 头节点 head ,请判断其是否为回文链表。

    如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。

    解决:

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode() : val(0), next(nullptr) {}
     7  *     ListNode(int x) : val(x), next(nullptr) {}
     8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
     9  * };
    10  */
    11 class Solution {
    12 public:
    13     ListNode* FindMidListNode(ListNode* head)
    14     {
    15         ListNode* slow = head;
    16         ListNode* fast = head;
    17 
    18         while (fast && fast->next && fast->next->next)
    19         {
    20             slow = slow->next;
    21             fast = fast->next->next;
    22         }
    23         return slow;
    24     }
    25 
    26     ListNode* ReverseLsit(ListNode* head)
    27     {
    28         if(head == nullptr || head->next == nullptr)
    29             return head;
    30         
    31         ListNode* vhead = new ListNode(-1);
    32 
    33         while(head)
    34         {
    35             ListNode* node = head->next;
    36             head->next = vhead->next;
    37             vhead->next = head;
    38             head = node;
    39         }
    40 
    41         return vhead->next;
    42     }
    43 
    44 
    45     bool isPalindrome(ListNode* head) {
    46         if(head == nullptr || head->next == nullptr)
    47             return head;
    48         ListNode* mid = FindMidListNode(head);
    49         ListNode* head1 = mid->next;
    50         mid->next = nullptr;
    51 
    52         head1 = ReverseLsit(head1);
    53 
    54         while(head && head1)
    55         {
    56             if(head->val != head1->val)
    57                 return false;
    58             head = head->next;
    59             head1 = head1->next;
    60         }
    61         
    62         return true;
    63     }
    64 };

    十六、复杂链表的复制

    题目链接:

      https://leetcode-cn.com/problems/LGjMqU/

    请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

    解决:

     1 class Solution {
     2 public:
     3     Node* copyRandomList(Node* head) {
     4         if(head == nullptr)
     5             return head;
     6         unordered_map<Node*, Node*> reg;
     7         Node* vhead = new Node(-1);
     8         Node* tail = vhead;
     9         Node* p = head;
    10         while(p){
    11             tail->next = new Node(p->val);
    12             tail = tail->next;
    13             reg[p] = tail;
    14             p = p->next;
    15         }
    16 
    17         while(head){
    18             if(head->random){
    19                 reg[head]->random = reg[head->random];
    20             } 
    21             head = head->next;
    22         }
    23         return vhead->next;
    24     }
    25 };

    十七、重排链表

    题目链接:

      https://leetcode-cn.com/problems/LGjMqU/

    给定一个单链表 L 的头节点 head ,单链表 L 表示为:

     L0 → L1 → … → Ln-1 → Ln 
    请将其重新排列后变为:

    L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …

    不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

    解决:

     1 class Solution {
     2 public:
     3     ListNode* FindMidListNode(ListNode* head)
     4     {
     5         ListNode* slow = head;
     6         ListNode* fast = head;
     7 
     8         while (fast && fast->next && fast->next->next)
     9         {
    10             slow = slow->next;
    11             fast = fast->next->next;
    12         }
    13         return slow;
    14     }
    15 
    16     ListNode* ReverseLsit(ListNode* head)
    17     {
    18         if(head == nullptr || head->next == nullptr)
    19             return head;
    20         
    21         ListNode* vhead = new ListNode(-1);
    22 
    23         while(head)
    24         {
    25             ListNode* node = head->next;
    26             head->next = vhead->next;
    27             vhead->next = head;
    28             head = node;
    29         }
    30 
    31         return vhead->next;
    32     }
    33 
    34     void reorderList(ListNode* head) {
    35         if(head == nullptr || head->next == nullptr)
    36             return;
    37         
    38         ListNode* mid = FindMidListNode(head);
    39         ListNode* newhead = mid->next;
    40         mid->next = nullptr;
    41 
    42         newhead = ReverseLsit(newhead);
    43 
    44         ListNode* node = head;
    45         while(newhead)
    46         {
    47             ListNode* temp = newhead->next;
    48 
    49             newhead->next = node->next;
    50             node->next = newhead;
    51 
    52             newhead = temp;
    53 
    54             node = node->next->next;
    55         }
    56 
    57     }
    58 };

    参考文章

    https://mp.weixin.qq.com/s/mFWLymqgmTf5gTvhpuXYBA

    https://mp.weixin.qq.com/s/jJQTykI02oc5Hc6ObPFbmQ

    本文来自博客园,作者:Mr-xxx,转载请注明原文链接:https://www.cnblogs.com/MrLiuZF/p/15225136.html

  • 相关阅读:
    POJ 2774 Long Long Message
    Jmeter学习——5
    Jmeter学习——4
    Jmeter学习——10
    Jmeter学习——9
    使用 JMeter 完成常用的压力测试 [转]
    Jmeter学习——3
    Jmeter学习——7
    Jmeter学习——11
    Jmeter学习——8
  • 原文地址:https://www.cnblogs.com/MrLiuZF/p/15225136.html
Copyright © 2011-2022 走看看