zoukankan      html  css  js  c++  java
  • 160. Intersection of Two Linked Lists

    ▶ 有两个单链表,从中间某个节点开始结点完全相同,找出该节点。

    A:          a1 → a2
                       ↘
                         c1 → c2 → c3
                       ↗            
    B:    b1 → b2 → b3

    ● 神奇的双指针法,34 ms,,详细步骤见代码注释(设两个单链表结点个数分别为 m 和 n,公共部分长为 k),时间复杂度 O(n),空间复杂度 O(1)

     1 class Solution
     2 {
     3 public:
     4     ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
     5     {
     6         if (headA == nullptr || headB == nullptr)
     7             return nullptr;
     8         ListNode *pa, *pb;
     9         for (pa = headA, pb = headB; pa != pb;) // 两指针分别指向两个单链表头部,每次循环将两指针向后一移一个结点
    10         {
    11             if (pa->next == nullptr && pb->next == nullptr)// 两个指针同时为空指针,说明两单链表没有公共结点(发生在第 m + n + 1 次循环)
    12                 return nullptr;
    13             pa = pa->next, pb = pb->next;       // 两指针分别向后移动一个结点
    14             if (pa == nullptr)                  // 其中一个指针超出某一条单链表的尾部的时候,让它指向另一条单链表的头部
    15                 pa = headB;
    16             if (pb == nullptr)
    17                 pb = headA;
    18         }
    19         return pa;                              // 两指针指向同一结点的时候,该节点就是公共链表部分的头结点(发生在第 m + n - k + 1 次循环)
    20     }
    21 };

    ● 双指针法高压版,36 ms

     1 ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
     2 {
     3     ListNode *cur1, *cur2;
     4     for(cur1 = headA, cur2 = headB;cur1 != cur2;)
     5     {
     6         cur1 = cur1 ? cur1->next : headB;
     7         cur2 = cur2 ? cur2->next : headA;
     8     }
     9     return cur1;
    10 }

     ● 代码,55 ms,便于理解的一个双指针法,加上蜜汁优化以后 24 ms,时间复杂度 O(n)

     1 static int x = []() 
     2 {    
     3     std::ios::sync_with_stdio(false);   // 关闭 cout 和 cin,使用 printf 和 scanf
     4     cin.tie(NULL);                      // 解除绑定 cin 和 cout
     5     return 0;
     6 } ();
     7 
     8 class Solution
     9 {
    10 public:
    11     ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
    12     {
    13         ListNode *cur1, *cur2;        
    14         int la, lb, diff;
    15         for (la = 0, cur1 = headA; cur1 != nullptr; cur1 = cur1->next, la++);// 统计两单链表的结点数 
    16         for (lb = 0, cur2 = headB; cur2 != nullptr; cur2 = cur2->next, lb++);
    17         cur1 = headA, cur2 = headB;
    18         diff = abs(la - lb);
    19         if (la > lb)
    20             for (; diff > 0; cur1 = cur1->next, diff--);            // 把公共结点之前不等长的部分跳过
    21         else
    22             for (; diff > 0; cur2 = cur2->next, diff--);
    23         for (; cur1 != cur2; cur1 = cur1->next, cur2 = cur2->next); // 共同前进直到两指针指向的结点相同,即为公共单链表头结点 
    24         return cur1;
    25     }
    26 };

    ● 代码,35 ms,强改指针地址

     1 class Solution//35
     2 {
     3 public:
     4     ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
     5     {
     6         ListNode *cur, *result;
     7         unsigned long *ptr;
     8         for (cur = headA; cur != nullptr;)// 默认结点二进制地址的末位为 0,把单链表 a 中各节点的 next 值二进制末位强行改成 1
     9         {
    10             ptr = (unsigned long *)&cur->next;
    11             cur = cur->next;
    12             *ptr |= 1;
    13         }
    14         for (cur = headB, result = nullptr; cur; cur = cur->next)// 沿着单链表 b 寻找 next 值被修改的结点,即为公共单链表的头结点 
    15         {
    16             if ((unsigned long)cur->next & 1)
    17             {
    18                 result = cur;
    19                 break;
    20             }
    21         }
    22         for (cur = headA; cur; cur = cur->next)// 把单链表 a 中各节点的 next 值改回去
    23         {
    24             ptr = (unsigned long *)&cur->next;
    25             *ptr &= (~0ULL << 1);
    26         }
    27         return result;
    28     }
    29 };

    ● 代码,38 ms,强改指针地址高压版,注释为等价的改地址方法

     1 class Solution//38
     2 {
     3 public:
     4     ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
     5     {
     6         if (headA == nullptr || headB == nullptr)
     7             return NULL;
     8         ListNode **pp, *q;
     9         for (pp = &(headA->next); (*(long*)pp |= 1L) != 1L;)            
    10             pp = &(((ListNode*)((char*)*pp - 1))->next);    // pp = (ListNode**)((char*)*pp - 1 + sizeof(int));
    11         for (q = headB; q != NULL && !((long)(q->next) & 1L); q = q->next);        
    12         for(pp = &(headA->next); (*(long*)pp &= -2L) != 0L;)            
    13             pp = &((*pp)->next);                            // pp = (ListNode**)((char*)*pp + sizeof(int));
    14         return q;
    15     }
    16 };

     ● 其他方法:暴力枚举,逐对检验,时间复杂度 O(mn),空间复杂度 O(1);其中一支单链表加入 hash 表,依另一支来查找,时间复杂度 O(m+n),空间复杂度 O(m) 或 O(n)

  • 相关阅读:
    [Javascript] Javascript numeric separators
    [RxJS] Extend Promises by Adding Custom Behavior
    [RxJS] Building an RxJS Operator
    [RxJS] Build an Event Combo Observable with RxJS (takeWhile, takeUntil, take, skip)
    [RxJS] Encapsulate complex imperative logic in a simple observable
    Android之Android软键盘的隐藏显示研究
    Android之LogUtil
    Android之使用XMLPull解析xml(二)
    Android之多媒体扫描过程
    Android之在Tab更新两个ListView,让一个listview有按下另个一个listview没有的效果
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/8380090.html
Copyright © 2011-2022 走看看