160.相交链表

160.相交链表

解题思路

package leadcode;

import leadcode.lib.ListNode;

/**
 * @author : icehill
 * @description : 相交链表
 * 编写一个程序,找到两个单链表相交的起始节点。
 * 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
 * 输出:Reference of the node with value = 8
 * 输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
 * 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
 * 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
 * 注意:
 * <p>
 * 如果两个链表没有交点,返回 null.
 * 在返回结果后,两个链表仍须保持原有的结构。
 * 可假定整个链表结构中没有循环。
 * 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
 * <p>
 * 来源:力扣(LeetCode)
 * 链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists
 * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
 * 解题思路:
 * 正常做法就是遍历链表A,存到哈希表中,然后再遍历链表B,判断B是是否有节点在哈希表中,
 * 时间复杂度:O(n) 空间复杂度:O(n)
 * 空间复杂度超过题目要求O(1)
 * <p>
 * 最佳解法:双指针
 * 分析:如果链表相交,则两个链表相交节点开始到最后一个节点肯定都相同,设公共链表为k,k肯定小于等于min(lengthA,lengthB)
 * 链表长度分别我lengthA,lengthB,两个链表的长度差|lengthA-lengthB|,所以,相交点肯定不在max(lengthA,lengthB)的第|lengthA-lengthB|
 * 个节点,那么,只要长的链表先走|lengthA-lengthB|步,则以后每步只需要判断指针A、B,即可知道从什么时候开始相交,这样就能求出相交点了
 * 官方解法:
 * 也是双指针,只不过更巧妙,也更好理解,省去了我们上面的分析过程
 * 设置链表分别由各自独立的链表+公共链表组成,listA+listC、listB+listC
 * 分别拼接上listB跟listA,则两个链表长度相同,步数一样,遍历一遍,必定到相交节点
 * (其实跟我想的解决方法一样,就是把长度不同的链表变为相同,只不过我用减法,它用加法)
 * @date : 2021-04-17
 */
public class Solution160 {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        int lengthA = 1;
        int lengthB = 1;
        ListNode tailA = headA;
        ListNode tailB = headB;
        //计算两个链表的长度,以及尾结点
        while (tailA.next != null) {
            tailA = tailA.next;
            lengthA++;
        }
        while (tailB.next != null) {
            tailB = tailB.next;
            lengthB++;
        }
        //尾结点不一样,则两个链表并不相交,返回null
        if (tailA != tailB) {
            return null;
        }
        ListNode tempHeadA = headA;
        ListNode tempHeadB = headB;
        if (lengthA > lengthB) {
            int length = lengthA - lengthB;
            while (length > 0) {
                tempHeadA = tempHeadA.next;
                length--;
            }
        } else if (lengthA < lengthB) {
            int length = lengthB - lengthA;
            while (length > 0) {
                tempHeadB = tempHeadB.next;
                length--;
            }
        }
        while (tempHeadA != tempHeadB) {
            tempHeadA = tempHeadA.next;
            tempHeadB = tempHeadB.next;
        }
        return tempHeadA;
    }

    /**
     * 官方解法
     * @param headA
     * @param headB
     * @return
     */
    public ListNode getIntersectionNodeTwo(ListNode headA, ListNode headB) {
        // 特判
        if (headA == null || headB == null) {
            return null;
        }

        ListNode head1 = headA;
        ListNode head2 = headB;

        while (head1 != head2) {
            if (head1 != null) {
                head1 = head1.next;
            } else {
                head1 = headB;
            }

            if (head2 != null) {
                head2 = head2.next;
            } else {
                head2 = headA;
            }
        }
        return head1;
    }
}

上一篇:leetcode之链表一: 160-相交链表


下一篇:CF990G GCD Counting(树上莫比乌斯反演,分层图,并查集)