爨爨爨好

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

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)

posted on 2018-01-30 11:30  爨爨爨好  阅读(148)  评论(0编辑  收藏  举报