两链表相交及其第一个节点
判断有环无环
判断有无环,如果有环返回第一个入环节点,如果无环返回null
使用额外空间:Set结构
沿着指针将a、b、c、d、e、c放入set结构中,每次放入前查看在set集合中是否存在;
若遍历到null都没有重复节点,那么链表为无环链表;
若有重复,链表有环,第一个重复的值即为第一个入环节点
不使用额外空间
如果一个链表无环,一定能够指向null
如果一个链表有环,最终它一定在一直循环
快慢指针:快指针一次走两步,慢指针一次走一步
如果一个链表无环,快指针先指向null
如果一个链表有环,快满指针一定会在某一时刻相遇
(不一定在入环节点相遇并且慢指针在环中转的圈数不超过两圈)
相遇之后,慢指针在原地,快指针回到起点,接下来快慢指针都走一步,两个指针一定会在入环节点相遇(数学证明)
//判断有环无环,有环返回第一个入环节点,无环返回null
public static Node getloopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
//快慢指针相遇的时候停止,如果快慢指针都从head出发,开始时相遇,所以快指针先走两步,慢指针走一步
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
if (fast.next == null || fast.next.next == null) {//无环
return null;
}
slow = slow.next;
fast = fast.next.next;
}
fast = head;//回到开头
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
对两个链表分类讨论
两个链表分别调用getloopNode方法
两个无环单链表
loop1 == null loop2 == null
不可能如左图所示,单链表只能有一个next指针;如果两链表相交,一定是右图所示
先遍历两个链表,记录两链表的长度;
比较链表最后一个Node,如果相等,则两链表相交;若不相等,则两链表不相交
长链表先走两个链表之间的长度差,之后两链表再一起走,两链表在第一个相交节点处相遇
//如果两个链表都无环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
int length1 = 0, length2 = 0;
//遍历链表1
while (head1.next != null) {//链表1在最后一个节点停
length1++;
head1 = head1.next;
}
//遍历链表2
while (head2.next != null) {//链表2在最后一个节点停
length2++;
head2 = head2.next;
}
if (head1 == head2) {//不相交
return null;
} else {
while(head1 != head2){//还没相遇
if (length1 > length2) {//链表1较长
length1--;
head1 = head1.next;
} else if (length1 < length2) {//链表2较长
length2--;
head2 = head2.next;
} else {//长链表先走了差值长度之后,两链表一起走直到相遇
head1 = head1.next;
head2 = head2.next;
}
}
}
return head1;
}
一个有环单链表,一个无环单链表
此种情况两链表不可能相交,一定会有某个节点有两个next指针
两个有环单链表
情况2:求相交节点 = 两无环单链表求相交节点
把入环节点看成结尾,终止节点为loop1==loop2
情况1和情况3:loop1继续向下走,如果在循环中没有遇到loop2,则两链表不相交;
如果在循环的过程中遇到了loop2,则两链表相交
返回的结果既可以是loop1,也可以是loop2,两个节点都是两链表的相交节点
//如果两个链表都有环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
//loop1 = getloopNode(head1); loop2 = getloopNode(head2);
public static Node bothLoop(Node head1, Node head2, Node loop1, Node loop2) {
if (loop1 == loop2) {//情况2
int length1 = 0, length2 = 0;
//遍历链表1
while (head1.next != null) {//链表1在最后一个节点停
length1++;
head1 = head1.next;
}
//遍历链表2
while (head2.next != null) {//链表2在最后一个节点停
length2++;
head2 = head2.next;
}
if (head1 == head2) {//不相交
return null;
} else {
while (head1 != head2) {//还没相遇
if (length1 > length2) {//链表1较长
length1--;
head1 = head1.next;
} else if (length1 < length2) {//链表2较长
length2--;
head2 = head2.next;
} else {//长链表先走了差值长度之后,两链表一起走直到相遇
head1 = head1.next;
head2 = head2.next;
}
}
}
return head1;
} else {//情况1和情况3
Node temp = loop1.next;
while (temp != loop1) {//在圈里面遍历
if (temp == loop2) {//遇到loop2,情况3
return loop1;//return loop2;
}
temp = temp.next;
}
return null;//情况1
}
}
回到题目
调用
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);
} else if (loop1 != null && loop2 != null) {
return bothLoop(head1,head2,loop1,loop2);
}else{
return null;
}
}
全代码
package linkedlist;
public class IntersectLinkedList {
class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
//判断有环无环,有环返回第一个入环节点,无环返回null
public static Node getloopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
//快慢指针相遇的时候停止,如果快慢指针都从head出发,开始时相遇,所以快指针先走两步,慢指针走一步
Node slow = head.next;
Node fast = head.next.next;
while (slow != fast) {
if (fast.next == null || fast.next.next == null) {//无环
return null;
}
slow = slow.next;
fast = fast.next.next;
}
fast = head;//回到开头
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
//如果两个链表都无环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
int length1 = 0, length2 = 0;
//遍历链表1
while (head1.next != null) {//链表1在最后一个节点停
length1++;
head1 = head1.next;
}
//遍历链表2
while (head2.next != null) {//链表2在最后一个节点停
length2++;
head2 = head2.next;
}
if (head1 == head2) {//不相交
return null;
} else {
while (head1 != head2) {//还没相遇
if (length1 > length2) {//链表1较长
length1--;
head1 = head1.next;
} else if (length1 < length2) {//链表2较长
length2--;
head2 = head2.next;
} else {//长链表先走了差值长度之后,两链表一起走直到相遇
head1 = head1.next;
head2 = head2.next;
}
}
}
return head1;
}
//如果两个链表都有环,判断两链表是否相交,相交则返回第一个相交节点,不相交则返回null
//loop1 = getloopNode(head1); loop2 = getloopNode(head2);
public static Node bothLoop(Node head1, Node head2, Node loop1, Node loop2) {
if (loop1 == loop2) {//情况2
int length1 = 0, length2 = 0;
//遍历链表1
while (head1.next != null) {//链表1在最后一个节点停
length1++;
head1 = head1.next;
}
//遍历链表2
while (head2.next != null) {//链表2在最后一个节点停
length2++;
head2 = head2.next;
}
if (head1 == head2) {//不相交
return null;
} else {
while (head1 != head2) {//还没相遇
if (length1 > length2) {//链表1较长
length1--;
head1 = head1.next;
} else if (length1 < length2) {//链表2较长
length2--;
head2 = head2.next;
} else {//长链表先走了差值长度之后,两链表一起走直到相遇
head1 = head1.next;
head2 = head2.next;
}
}
}
return head1;
} else {//情况1和情况3
Node temp = loop1.next;
while (temp != loop1) {//在圈里面遍历
if (temp == loop2) {//遇到loop2,情况3
return loop1;//return loop2;
}
temp = temp.next;
}
}
return null;//情况1
}
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);
} else if (loop1 != null && loop2 != null) {
return bothLoop(head1,head2,loop1,loop2);
}else{
return null;
}
}
}