链表相交问题
判断两个链表进行相交,其中这两个链表又有可能是有环的,也有可能是无环的,这里种情况的判断逻辑不一样,所以我们要先进行判断。
判断链表是否有环
判断一个链表是否有环,有两种情况可以实现。
第一种方法,一值是把这个链表放入HashSet种,然后再判断,把next放入set中,如果next为null那就是无环,最后指向null。如果是添加到HasHSet失败,那么是set中有相同元素则有环,其中添加失败那个点就是入环节点。这种方法较简单,就不过多分析了,代码也很简单,主要看下面这种情况。
第二种情况,是最常用的情况,就是使用快慢双指针,慢指针和快指针从head开始,慢指针走一步,快指针走两步。如果快指针在行走过程中为null则就是无环,若快慢指针进行相遇了,那么就说明有环,只要把快指针放回head,把它的步数调到1,再次相遇时就是入环节点。这是经典的追赶问题,感兴趣的可以自己网上找证明。
判断是否环的代码
public Node getLoopNode(Node head){
if (head == null || head.next == null || head.next.next == null){
return null;
}
Node fast = head.next.next;
Node slow = head.next;
while (fast != slow){
if (fast.next.next == null || fast.next == null){
return null;
}else {
fast = fast.next.next;
slow = slow.next;
}
}
fast = head;
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
判断完链表是否有环了,我们就可以进行分情况讨论,
在开始讨论时先明确两个链表相交后,一定只有一条路劲,因为相交节点为同一个节点,而又只有一个next指针,那么肯定只有一条路劲。
无环情况
在这个前提下,我们知道,相交后只有一个路劲。主体思想是这样的,先遍历两个链表统计长度,或者获取原先的链表在插入时维护的长度也可以。计算出它们的差值,先让长链表去走差值的步数,然后两个再一起走,过程中出现节点相等则为相交。
如果一起途中相等那肯定相交,如果无,那就没有相交。
public Node noLoop(Node head1,Node head2){
if (head1 == null || head2 == null){
return null;
}
Node cur1 = head1;
int n1 = 0;
Node cur2 = head2;
int n2 = 0;
while(cur1.next != null){
n1++;
cur1 = cur1.next;
}
while(cur2.next != null){
n2++;
cur2 = cur2.next;
}
//最后节点都不相同肯定是无相交
if (cur1 != cur2){
return null;
}
//重新赋值
cur1 = n1 - n2 > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
int n = Math.abs(n1 - n2);
//先走差值步
while (n != 0){
n--;
cur1 = cur1.next;
}
//来到这判断已经是有相交的,不然已经return了 再一起走找相交
while(cur1 != cur2){
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
若一个有环,一个无环
其实这种可能并不存在,因为前面,已经说了若两个链表相交,后面肯定同一路劲,不可能有这种情况。要么都有环,要么都无环
两个都有环
这里又分为3种情况
1,入环节点为0个,就是不相交情况。
2,入环节点为一个
3,入环节点有两个
对于情况2,因为它和上面的无环相交问题的性质是一样的,它在入环前已经,相交,前面的相交就可以把它看作无环相交,
情况3只要走一圈,判断过程种节点是否相等,如果有和另外一个链表的入环节点相交那就是情况3,无就是情况1.
//l1为第一个入环节点 l2为第2个入环接待你
public Node bothLoop(Node head1,Node head2,Node l1,Node l2){
if (head1 == null || head2 == null){
return null;
}
if (l1 == l2){//情况2只有一个节点
return noLoop(head1,head2);
}else {
Node cur1 = l1.next;
//走一圈
while(cur1 != l1){
//与另一个入环节点相交 情况3
if (cur1 == l2){
return l1;
}
cur1 = cur1.next;
}
//情况1
return null;
}
}
主方法
public boolean isIntersect(Node h1,Node h2){
Node l1 = getLoopNode(h1);
Node l2 = getLoopNode(h2);
//无环情况
if (l1 == null && l2 == null){
return noLoop(h1,h2) != null;
}
//有环情况
if (l1 != null && l2 != null){
return bothLoop(h1,h2,l1,l2) != null;
}
return false;
}
以上就是关于两链表相交的全部内容.