给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
    图示两个链表在节点 c1 开始相交:
    image.png

    1. /**
    2. * 利用哈希表
    3. *
    4. * @param headA
    5. * @param headB
    6. * @return
    7. */
    8. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    9. Set<ListNode> headASet = new HashSet<>();
    10. while (headA != null) {
    11. headASet.add(headA);
    12. headA = headA.next;
    13. }
    14. while (headB != null) {
    15. if (headASet.contains(headB)) {
    16. return headB;
    17. }
    18. headB = headB.next;
    19. }
    20. return null;
    21. }

    如果不借用哈希表,那么则需要借助双指针来实现

    由于两条链表的长度可能不同,两条链表之间的节点无法对应:
    image.png

    如果用两个指针 p1 和 p2 分别在两条链表上前进,并不能同时走到公共节点,也就无法得到相交节点 c1。

    解决这个问题的关键是,通过某些方式,让 p1 和 p2 能够同时到达相交节点 c1

    所以,我们可以让 p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B之后开始遍历链表 A,这样相当于「逻辑上」两条链表接在了一起。

    如果这样进行拼接,就可以让 p1 和 p2 同时进入公共部分,也就是同时到达相交节点 c1:
    image.png

    1. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    2. // p1 指向 A 链表头结点 p2 指向 B 链表头结点
    3. ListNode p1 = headA;
    4. ListNode p2 = headB;
    5. while(p1 != p2) {
    6. // p1 走一步,如果走到 A 链表末尾,转到 B 链表
    7. if (p1 == null) {
    8. p1 = headB;
    9. } else {
    10. p1 = p1.next;
    11. }
    12. // p2 走一步,如果走到 B 链表末尾,转到 A 链表
    13. if (p2 == null) {
    14. p2 = headA;
    15. } else {
    16. p2 = p2.next;
    17. }
    18. }
    19. return p1;
    20. }