1.分析问题:
链表分为有环和无环,如果两个链表存在相交,则只有两种可能,两个链表都无环或者都有环。
下面分别讨论。
2.判断链表是否有环
2.1定义链表
//单向链表
public static class LinkNode{
int data;
LinkNode next = null;
public LinkNode(int data) {
this.data = data;
next = null;
}
}
2.2判断是否有环
判断是否有环,有环返回入口点,无环返回null。
public static LinkNode isLoop(LinkNode node) {
if (node == null) {
return null;
}
LinkNode slow = node;
LinkNode fast = node;
while(slow.next!=null && fast.next!=null) {
//一次走一步
slow = slow.next;
//一次走两步
fast = fast.next;
if (fast!=null) {
fast = fast.next;
}
/**
* 特别注意:
* 如果存在循环,则在慢指针走完环前,总会和快指针相遇,因为快指针比慢指针快一倍哦
* 从头指针和相遇点同时向后走,相遇的点必定是入口点。(这里要好好思考一下)
* 比如起点是A,入口点B,相遇点C,环一圈距离记为L,相遇是快指针比慢指针多走一圈,故AC = L,
* AC - BC = L - BC,所以AB = L - BC,即下次相遇的点必定是入口点B
*/
if (slow == fast) {//说明有环
fast = node;//回到头指针
while(slow!=fast) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
return null;
}
3.无环链表相交情况
两个无环链表比较,返回第一个交点,不相交返回null
private static LinkNode getNoLoop(LinkNode head1, LinkNode head2) {
int len1 = 1;//第一个链表长度
int len2 = 1;//第二个链表长度
LinkNode temp1 = head1;
LinkNode temp2 = head2;
//第一个链表的最后一个元素
while(temp1.next!= null) {
temp1 = temp1.next;
len1++;
}
//第二个链表的最后一个元素
while(temp2.next!= null) {
temp2 = temp2.next;
len2++;
}
//尾部不同,没有相交的点
if (temp1.data !=temp2.data) {
return null;
}
//相交情况
int cur = Math.abs(len1-len2);//长度差
//temp1记录长的链表,temp2记录短的链表
if (len1>len2) {
temp1 = head1;
temp2 = head2;
}else {
temp1 = head2;
temp2 = head1;
}
for (int i = 0; i < cur; i++) {
temp1 = temp1.next;
}
//判断链表是否相同,相同则停止循环(这里指两个链表各个节点数据是否相同,
//不是链表是否相同,这里省略比较
while(temp1!=temp2) {
System.out.println(temp1.data+ " "+ temp2.data);
temp1 = temp1.next;
temp2 = temp2.next;
}
return temp1;
}
4.有环链表相交情况
有环链表相交分两种情况:
case1:入口点相同(可转化为无环)
case2:入口点不同
分别讨论:
private static LinkNode getBothLoop(LinkNode head1, LinkNode loop1, LinkNode head2, LinkNode loop2) {
if (loop1 == loop2) {//入口点相同,在环外找(包括环的入口点)
int len1 = 1;//第一个链表长度
int len2 = 1;//第二个链表长度
LinkNode temp1 = head1;
LinkNode temp2 = head2;
//第一个链表的最后一个元素
while(temp1.next!= loop1) {
temp1 = temp1.next;
len1++;
}
//第二个链表的最后一个元素
while(temp2.next!= loop2) {
temp2 = temp2.next;
len2++;
}
//相交情况
int cur = Math.abs(len1-len2);//长度差
//temp1记录长的链表,temp2记录短的链表
if (len1>len2) {
temp1 = head1;
temp2 = head2;
}else {
temp1 = head2;
temp2 = head1;
}
for (int i = 0; i < cur; i++) {
temp1 = temp1.next;
}
while(temp1!=temp2) {
temp1 = temp1.next;
temp2 = temp2.next;
}
return temp1;
}else {//入口点不同(在环上找)
LinkNode cur = loop1.next;
while(cur!=loop1) {//遍历环上所有节点
if (cur != loop2) {
cur = cur.next;
}else {
return loop1;
}
}
return null;
}
}