问题

编写一个程序,找到两个单链表相交的起始节点。 如下面的两个链表:

graph LR
    a1 --> a2
    b1 --> b2 --> b3
    
    a2 --> c1
    b3 --> c1
    c1 --> c2 --> c3

在节点开始相交。 示例 1:

graph LR
    a1[4] --> a2[1]
    b1[5] --> b2[0] --> b3[1]
    
    a2 --> c1[8]
    b3 --> c1
    c1 --> c2[4] --> c3[5]

输入: intersectVal = 8, listA = , listB = , skipA = 2, skipB = 3 输出: Reference of the node with value = 8 输入解释: 相交节点的值为 (注意,如果两个列表相交则不能为 )。从各自的表头开始算起,链表 A 为 ,链表 B 为 。在 A 中,相交节点前有个节点;在 B 中,相交节点前有个节点。

示例 2:

graph LR
    a1[0] --> a2[9] --> a3[1]
    b1[3]
    
    a3 --> c1[2]
    b1 --> c1
    c1 --> c2[4]

输入: intersectVal = 2, listA = , listB = , skipA = 3, skipB = 1 输出: Reference of the node with value = 2 输入解释: 相交节点的值为 (注意,如果两个列表相交则不能为 )。从各自的表头开始算起,链表 A 为 ,链表 B 为 。在 A 中,相交节点前有 个节点;在 B 中,相交节点前有 个节点。

示例 3:

graph LR
    a1[2] --> a2[6] --> a3[4]
    b1[1] --> b2[5]

输入: intersectVal = 0, listA = , listB = , skipA = 3, skipB = 2 输出: null 输入解释: 从各自的表头开始算起,链表 A 为 ,链表 B 为 。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 解释: 这两个链表不相交,因此返回 null。

注意:

  1. 如果两个链表没有交点,返回 null.
  2. 在返回结果后,两个链表仍须保持原有的结构。
  3. 可假定整个链表结构中没有循环。
  4. 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

解法

注意到这样一个事实,如果两个链表相交,那么在相交节点前面的两个分叉上,正好相差这两个链表长度之差的元素个数。因此,首先遍历两个链表,得到链表长度,然后长度更长的链表先往前走长度之差的步数,然后后面两个链表向前推进到相等即为结果。

代码

java

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        //首先遍历两个链表查询长度
        int l1 = 0;
        ListNode h1 = headA;
        while (h1 != null) {
            h1 = h1.next;
            l1++;
        }
        int l2 = 0;
        ListNode h2 = headB;
        while (h2 != null) {
            h2 = h2.next;
            l2++;
        }
 
        //长度更长的那个需要先走几步,直到两个长度相等时才同时前进。
        h1 = headA;
        h2 = headB;
        int dif = l1-l2;
        if (dif > 0) {
            while(dif-- >0) {
                h1 = h1.next;
            }
        } else if (dif < 0) {
            while(dif++ < 0) {
                h2 = h2.next;
            }
        }
        int len = Math.min(l1, l2);
        while (h1 != h2){
            h1 = h1.next;
            h2 = h2.next;
        }
        return h1;
    }
}