Intersection of two linkedlist

这道题实际上比LC上那道题要复杂,LC上那道题assume两个链表都是无环的。然而实际情况有多种可能:一个有环、一个无环;两个都有环;两个都没有环。

在这里要先理解什么是LinkedList的相交。形象一点说,链表的相交指的是"Y" 型相交,而不是"X"型相交。也就是说,一旦到达开始相交的节点,后面直到链表尾端都是一样的。而不能只是一部分相同,后半段又分叉。

Intersection of two linkedlist_第1张图片
image.png

首先是两个都无环的情况,这个就跟LC上的题解法一样,只需要先移动两条链表的长度差,再一起出发,第一个相同的节点就是交点。
第二种情况是一个有环,一个无环,不难想到,这种情况不可能相交。
第三种情况是两个都有环。

判断环的代码:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
//is one node whose next pointer points to itself called a circle?
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null){
            return false;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast){
                return true;
            }
        }
        return false;
    }
}

两个都存在环的时候,首先判断是否有交点. 判断方法是可以用查找是否有环的方法找到快慢指针相遇点,它肯定在环内。如果两个有环链表相交,它们会公用一个环。我们移动快指针,如果循环一圈再次与慢指针相遇,说明它们相交。

// 判断两个有环单链表是否相交
public boolean isisIntersectWithLoop(ListNode headA, ListNode headB) {
    if (null == headA || null == headB) {
        return false;
    }
    if (headA == headB) {
        return true;
    }
    headA = hasCycle(headA);
    headB = hasCycle(headB);
    // 没有环,则退出
    if (null == headA || headB) {
        return false;
    }
    ListNode p = headB.next;
    // p 在环内循环一次,直到与 headA 相遇
    while (p != headB) {
        if (p == headA) {
            return true;
        }
        p = p.next;
    }
    return false;
}
// 判断单链表是否有环,并返回环内的某一节点
public ListNode hasCycle(ListNode head) {
    if (null == head) {
        return null;
    }
    ListNode slow = head;
    ListNode fast = head;
    while (null != fast.next && null != fast.next.next) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow) {
            return slow;
        }
    }
    return null;
}

找第一个相交的节点,可能有两种可能:交点在环外,交点在环内。


Intersection of two linkedlist_第2张图片
image.png

所以我们要先求两个链表的入环节点看是否相等。找入环节点方法见142. Linked List Cycle II, 证明:


Intersection of two linkedlist_第3张图片
image.png
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null){
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow){
                break;
            }
        }
        if (fast == null || fast.next == null){
            return null;
        }
        fast = head;
        while (fast != slow){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

如果两个链表环的入口处是相同的,那么它们求intersection的方法就可以跟无环的两个链表求法类似。它们的交点肯定在入口点之前或者就是入口点,所以只需要算出它们到入口点的距离差,然后长的先走相应步数让他们在同一起点,一起走走到第一个相同节点就是交点;如果两个链表环的入口处不相同,则随便返回一个入口处即可。


Intersection of two linkedlist_第4张图片
image.png

你可能感兴趣的:(Intersection of two linkedlist)