两个单链表相交的一系列问题

简介: 两个单链表相交的一系列问题

题目

给定两个可能有环也可能无环的单链表,头节点head1和head2。

请实现一个函数,如果两个链表相交,请返回相交的第一个节点。如果不相交,返回null。

要求:如果两个链表长度之和为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)

思路: 如果要解决上面的问题,就需要会:

  • 如何判定有环并找到链表第一个入环节点
  • 链表相交的情况

如何判定有环并找到链表第一个入环节点

1.使用额外空间Set

2.快慢指针法

如果有环,快慢指针肯定会相遇,并且转的圈数不超过两圈,因为快指针的速度是慢指针的两倍,在慢指针转完一圈时如果还没相遇就是无环,如果有环在慢指针转完一圈之前肯定会在环上相遇。 相遇之后,慢指针以这个相遇点为起点,快指针以链表头为起点,然后两个指针保持速度一致,每次只走一步,相遇的点就是入环的第一个节点处。

// 找到链表第一个入环节点,如果无环,返回null
public static Node getLoopNode(Node head){
    if(head == null || head.next == null || head.next.next == null){
        return null;
    }
    Node n1 = head.next;   // n1 -> show
    Node n2 = head.next.next;    // n2->fast
    while(n1 != n2){
        if(n2.next == null || n2.next.next == null){
            return null;
        }
        n2 = n2.next.next;
        n1 = n1.next;
    }
    n2=head;   // n2 -> walk again from head
    while(n1 != n2){
        n1 = n1.next;
        n2 = n2.next;
    }
    return n1;
}
复制代码

两个链表是否相交

1.两个链表都无环的情况

分析

如果两个链表都是无环,如果相交那么就是"Y"型,也就是说,两个链表的后半部分是相同部分。不可能是"X"型,因为是单链表只会有一个next指针,如果是"X"型,就肯定会有一个节点有两个next指针,这是不合理的。

思路

  • 1.先判断两个链表的尾部节点是否是同一个,如果不是就说明不相交,如果是进入第2个判断
  • 2.求出两个链表的长度差n,较长的链表先走n步后,两个链表再一起走,相遇的第一个点就是相交的点。
// 如果两个链表都无环,返回第一个相交节点,如果不相交,返回null
public static Node noLoop(Node head1, Node head2){
    if(head1 == null || head2 == null){
        return null;
    }
    Node cur1 = head1;
    Node cur2 = head2;
    int n = 0;  // 长度,遍历链表1的时候n++,遍历链表2的时候n--,最后的值就是链表1与2的长度差
    while(cur1.next != null){
        n++;
        cur1 = cur1.next;
    }
    while(cur2.next != null){
        n--;
        cur2 = cur2.next;
    }
    if(cur1 != cur2){
        return null;
    }
    cur1 = n > 0 ? head1 : head2;   // 谁长,谁的头变cur1
    cur2 = cur1 == head1 ? head2 : head1;   // 谁短,谁的头变成cur2
    n = Math.abs(n);
    while(n != 0){
        n--;
        cur1 = cur1.next;
    }
    while(cur1 != cur2){
        cur1 = cur1.next;
        cur2 = cur2.next;
    }
    return cur1;
}
复制代码

2.一个链表无环,另一个链表有环的情况

这种情况不存在相交的情况

3.两个链表都有环的情况

两个链表都有环,主要分为下面三种情况:

  • 1)不相交,各自成环
  • 2)相交,共用环,入环节点是同一个
  • 3)相交,共用环,入环节点不是同一个

网络异常,图片无法展示
|

实现思路

  • 首先判断入环节点是否同一个,即loop1是否等于loop2,如果是就是第二种情况
  • loop1继续转圈,如果在转的过程中能遇到loop2,就是情况三,否则就是情况一
// 两个有环链表,返回第一个相交节点,如果不相交返回null
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2){
    Node cur1 = null;
    Node cur2 = null;
    if(loop1 == loop2){
        cur1 = head1;
        cur2 = head2;
        int n = 0;
        while(cur1 != loop1){
            n++;
            cur1 = cur1.next;
        }
        while(cur2 != loop2){
            n--;
            cur2 = cur2.next;
        }
        cur1 = n > 0 ? head1 : head2;
        cur2 = cur1 == head1 ? head2 : head1;
        n = Math.abs(n);
        while(n != 0){
            n--;
            cur1 = cur1.next;
        }
        while(cur1 != cur2){
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1;
    }else{
        cur1 = loop1.next;
        while(cur1 != loop1){
            if(cur1 == loop2){
                return loop1;
            }
            cur1 = cur1.next;
        }
        return null;
    }
}
// 主函数
public static Node getIntersectNode(Node head1, Node head2){
    if(head1 == null || head2 == null){
        return null;
    }
    Node loop1 = getLoopNode(head1);
    Node loop2 = getLoopNode(head2);
    if(loop1 == null && loop2 == null){
        return noLoop(head1, head2);
    }
    if(loop1 != null && loop2 != null){
        return bothLoop(head1, loop1, head2, loop2);
    }
    return null;
}



相关文章
|
7月前
|
C++ Python
leetcode-160:相交链表
leetcode-160:相交链表
57 0
LeetCode | 160. 相交链表
LeetCode | 160. 相交链表
|
7月前
|
C++
[leetcode 链表] 反转链表 vs 链表相交
[leetcode 链表] 反转链表 vs 链表相交
|
7月前
力扣160:相交链表
力扣160:相交链表
34 0
|
7月前
leetcode:160. 相交链表
leetcode:160. 相交链表
35 0
|
7月前
|
C++
相交链表(C++)
相交链表(C++)
50 0
【链表】160. 相交链表
【链表】160. 相交链表
|
存储
160.相交链表(LeetCode)
160.相交链表(LeetCode)
力扣160. 相交链表
力扣160. 相交链表
45 0