160. Intersection of Two Linked Lists

来源:互联网 发布:nba2k17帅气捏脸数据 编辑:程序博客网 时间:2024/06/15 05:46

做这道题目的时候顺带复习了一下找带环单链表的环入口,在第二种解法中将作解释。

描述:
Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:

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

意:找到其中的相交节点(修改一下也可以叫做环的入口节点),很明显,图中的入口是c1.

解法1

分析:
我们可以将这两条链表看成是两条平行的线段,其中后面的一段线段是一定相同的,只不过前面一段有长有短:

    a1  a2  c1  c2  c3 b1  b2  b3  c1  c2  c3//很容易看出来其实就是c1前面的一部分元素个数不同

那么我们可以这样来使得它们同步起来:
1.先让a,b两条链走完统计出两条链表的长度为a1,a2
2.找出其中长的一条链,让它先往前走abs(a1-a2)个节点,这时候将长链表中多余的元素走完了
3.另外一条链也同时开始走,这时候两条链表剩余的长度是一样的,走到第一个相等的节点就是入口节点了。

C++

class Solution {public:    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {        ListNode* A = headA;        ListNode* B = headB;        int a = 0;        int b = 0;        while(A){            a++;            A = A->next;        }        while(B){            b++;            B = B->next;        }        //这里需要加一个判断两条链表没有交点的情况,注意        if(A != B){return NULL;}        int Max = max(a,b) - min(a,b); //或者abs(a-b),一样        if(a>b){            while(Max){                headA = headA->next;                Max--;            }        }        else{            while(Max){                headB = headB->next;                Max--;            }        }        while(headA != headB){            headA = headA->next;            headB = headB->next;        }        return headA;} };

python:

class Solution(object):    def getIntersectionNode(self, headA, headB):        A = headA        B = headB        a = 0        b = 0        while A is not None:            a += 1            A = A.next        while B is not None:            b += 1            B = B.next        if A != B:            return None        Max = abs(a-b)        if a > b:            while Max:                headA = headA.next                Max -= 1        else:            while Max:                headB = headB.next                Max -= 1        while headA != headB:                headA = headA.next                headB = headB.next        return headA

解法二:

分析:
这道题目其实和我们之前做过的一道判断单链表是否有环很相像,我们只需要稍微构造一下即可还原那道题目的样子。
比如还是上面的例子

A:          a1 → a2                   ↘                     c1 → c2 → c3                   ↗            B:     b1 → b2 → b3//我们这做,将c3 -> next = b1

那么就变成如下的图了:
这里写图片描述

这样就构成一个环了,关于环我们可以了解到:使用两个指针,一快一慢,我们能根据两个指针是否相交来判断这个链表是不是有环,但是要找到环的入口呢?这里我们需要通过一些推导:
参考了这篇博客
大致过程咱们也来推导一下,加深自己的理解:
这里写图片描述

这里是黑色的部分是慢指针走过的路径,红色部分是快指针绕环经过的路径:
假设

L1:平行线的长度,o点到m点L2:整个环的长度L_m_n:入口点m和相交点n的距离,按着箭头指示的方向走slow_len : 慢指针走过的距离k : 快指针走过的圈数我们能得到几个公式:1.L1 + L_m_n = slow_len2.slow_len = L2 - L_m_n3.L1 + k*L2 + L_m_n = slow_len综合这3个等式可以得到:L1 = k*L2 - L_m_n = (k-1)L2 + (L2 - L_m_n)这个式子拿到图中就是:L1的距离 = 环的整数倍数(k-1倍) + 交点与环入口的距离,更具体一点:就是红色线段和平行线段等长也就是说,找到交点之后,再往前走L1步就能到达环的入口,这时候让链表头和这个交点同时向前走,如果是有环,则必然能相交,否则为nullptr。

C++

//时间复杂度是O(n),空间复杂度是O(1)class Solution {public:    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {        ListNode* head = headA;        if (headA == NULL || headB == NULL) return NULL;        while(headA->next){            headA = headA->next;        }        headA->next = headB;        ListNode* res = iscycle(head);        headA->next = nullptr;        return res;    }    ListNode* iscycle(ListNode* head){        ListNode* slow = head;        ListNode* fast = head;        while(slow && fast){            slow = slow->next;            fast = fast->next;            if(fast){                fast = fast->next;            }            if(fast == slow){                break;            }        }        if (fast == nullptr){return nullptr;}          slow = head;        while (slow != fast) {              slow = slow->next;              fast = fast->next;          }          return fast;         }};

python:

class Solution(object):    def getIntersectionNode(self, headA, headB):        if not headA or not headB:            return None        ptr = headA        while ptr.next != None:            ptr = ptr.next        ptr.next = headB        res = self.iscycle(headA)        ptr.next = None        return res    def iscycle(self,head):        slow = head        fast = head        while slow and fast:            slow = slow.next            fast = fast.next            if fast:                fast = fast.next            if fast == slow:                break        if fast == None:            return None        slow = head        while slow != fast:            slow = slow.next            fast = fast.next        return fast
0 0