Leetcode 160. 链表相交(Intersection of two linked lists lcci)

发布时间 2023-08-18 23:49:45作者: Ahci

题目链接

给定两个单链表的头节点headA和headB, 请找出并返回两个单链表相交的起始节点. 如果两个链表没有交点, 返回null.

图示两个链表在节点c1开始相交, 题目数据保证整个链式结构中不存在环.

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

提示:

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 0 <= m, n <= 3 * 104
  • 1 <= Node.val <= 105
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listA 和 listB 没有交点,intersectVal 为 0
  • 如果 listA 和 listB 有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]

思路

这道题首先想到的是将链表A的每个节点存入Set, 再使用链表B去挨个比对, 若比对成功返回, 否则返回null即可.

第二想到的方法是使两个链表的临时指针在同一位置上, 同时前进, 比对指向的值是否一致.

在看到Leetcode题解后发现还有第三种方法, 双指针法. 首先在链表A和B处各定义一个临时指针, 同时向前遍历, 若指针为空则指向另一条链表继续遍历, 当两指针指向同一节点时返回目标节点, 或返回null.

代码实现

HashSet:

/**
 * 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) {
        Set<ListNode> set = new HashSet<ListNode>();
        ListNode temp = headA;

        while(temp != null) {
            set.add(temp);
            temp = temp.next;
        }

        temp = headB;

        while(temp != null) {
            if(set.contains(temp)) {
                return temp;
            }
            temp = temp.next;
        }

        return null;
    }
}

双指针法:

/**
 * 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;
        }

        ListNode tempA = headA;
        ListNode tempB = headB;

        while(tempA != tempB) {
            tempA = tempA == null ? headB : tempA.next;
            tempB = tempB == null ? headA : tempB.next;
        }

        return tempA;
    }
}

暴力解法:

/**
 * 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) {
        int lenA = 0;
        int lenB = 0;
        ListNode tempA = headA;
        ListNode tempB = headB;

        // 确定链表A的长度
        while(tempA != null) {
            tempA = tempA.next;
            lenA++;
        }

        // 确定链表B的长度
        while(tempB != null) {
            tempB = tempB.next;
            lenB++;
        }

        // 临时节点复位
        tempA = headA;
        tempB = headB;

        // 使链表A为最长的
        if(lenB > lenA) {
            // swap(lenA, lenB)
            int tempLen = lenA;
            lenA = lenB;
            lenB = tempLen;

            // swap(tempA, tempB)
            ListNode tempNode = tempA;
            tempA = tempB;
            tempB = tempNode;
        }

        int gap = lenA - lenB;  // 长度差

        // 使tempA和tempB在同一起点上
        while(gap-- > 0) {
            tempA = tempA.next;
        }

        // 遍历
        while(tempA != null) {
            if(tempA == tempB) {
                return tempA;
            }
            tempA = tempA.next;
            tempB = tempB.next;
        }

        return null;
    }
}