题目:给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。
思路:题目要求就是简单的判断是否相交,更加通用的情况是判断有没有相交,如果相交返回第一个相交结点,如果不相交返回null。这道题目是前面两道题目的综合,由于不明确链表里面是否有环,而有环和没环情况下找出第一个相交结点是不同的,因此要分情况来考虑
①特殊输入,head1、head2有一个为null,不相交,交点为null;
②判断head1,head2是否有环—LB9,将这个处理过程提取为一个单独的函数
(1)设置两个指针pfast,pslow进行遍历,如果有环,记录返回入环的第一个结点(即如果pfast.next==null时返回无环,否则求得交点meetingNode,再返回入环结点);
③根据有没有环分别处理
(1)如果链表1,链表2都没环,就是比较两个无环单链表是否相交并返回第一个交点的问题;(LB10)
(2)如果一个链表有环而另一个链表无环说明必定没有交点;
(3)如果链表1,链表2都有环,就是判断两个有环链表是否相交,如果相交返回第一个交点,如果不相交返回null;(LB11)
import java.util.*;
public class ChkIntersection {
//为了代码复用,设置一个标志位,用于表示当参数为null时的情形
//ListNode mark=new new ListNode(0);
public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {
//由于题目仅仅要求判断是否相交,但是采用更加通用的方法返回第一个相交的结点
ListNode returnFirstIntersectionNode=this.returnFirstIntersectionNode(head1,head2,adjust0,adjust1);
return returnFirstIntersectionNode==null ? false:true;
}
//给定两个链表head1,head2,如果相交,返回相交的第一个结点,否则返回null
public ListNode returnFirstIntersectionNode(ListNode head1, ListNode head2, int adjust0, int adjust1){
//特殊输入判断
if(head1==null||head2==null) return null;
//判断链表是否有环,如果有环返回第一个入环结点
ListNode entryNodeOfLoop1=this.entryNodeOfLoop(head1);
ListNode entryNodeOfLoop2=this.entryNodeOfLoop(head2);
//一个链表有环,一个没有环则必定不会相交
if(entryNodeOfLoop1==null&&entryNodeOfLoop2!=null) return null;
if(entryNodeOfLoop1!=null&&entryNodeOfLoop2==null) return null;
ListNode intersectionNode=null;
if(entryNodeOfLoop1!=null&&entryNodeOfLoop2!=null){
//此时,即两个链表都有环,且已经得到入环结点,即寻找两个有环链表的相交结点,调用方法intersectionNodeWithLoop()
intersectionNode=this.intersectionNodeWithLoop(head1,entryNodeOfLoop1,head2,entryNodeOfLoop2);
}else{
//如果两个链表都没有环就是寻找两个无环链表的相交结点的问题,调用方法intersectionNodeWithoutLoop()
intersectionNode=this.intersectionNodeWithoutLoop(head1,head2,null);
}
return intersectionNode;
}
//已知head!=null判断输入的链表是否有环,如果有环则返回环的第一个结点
public ListNode entryNodeOfLoop(ListNode head){
//如果只有一个结点则无环
if(head.next==null) return null;
//定义两个指针
ListNode pfast=head;
ListNode pslow=head;
pslow=pslow.next;
pfast=pfast.next.next;
while(pslow!=pfast){
//如果链表有尽头那么一定无环
if(pfast==null||pfast.next==null) return null;
pslow=pslow.next;
pfast=pfast.next.next;
}
//此时说明一定有环,记录pfast和pslow在环中的交点
ListNode meetingNode=pslow;
//得到入环结点
ListNode p=head;
while(p!=pslow){
p=p.next;
pslow=pslow.next;
}
return p;
}
//已知两个无环链表head1,head2,判断是否相交,若是返回第一个相交结点,否则返回null,为了代码复用,扩展为在head到tailHead之间找相交结点
public ListNode intersectionNodeWithoutLoop(ListNode head1,ListNode head2,ListNode tailNode){
//已知head1,head2不为空,即Y字形结构的比较,先得到链表的长度,为了代码复用,此时是求从head到tailHead结点的长度
int length1=listLength(head1,tailNode);
int length2=listLength(head2,tailNode);
ListNode longList=null;
ListNode shortList=null;
int diff=0;
if(length1<length2){
longList=head2;
shortList=head1;
diff=length2-length1;
}else{
longList=head1;
shortList=head2;
diff=length1-length2;
}
//长链表先走diff
for(int i=0;i<diff;i++){
longList=longList.next;
}
//开始一起向下移动并逐一进行不比较
while(longList!=tailNode&&shortList!=tailNode){
if(longList==shortList) return longList;
longList=longList.next;
shortList=shortList.next;
}
//如果直到末尾还是不同说明链表没有相交
return null;
}
//给定一个无环链表head,求出链表的长度,扩展为求出链表从head到指定结点tailNode的长度
public int listLength(ListNode head,ListNode tailNode){
//已知链表不为null
int count=0;
while(head!=tailNode){
head=head.next;
count++;
}
return tailNode==null?count:count++;
}
//已知两个有环的链表head1,head2,已经得到了有环链表的入环结点,判断是否相交,找出其第一个交点
public ListNode intersectionNodeWithLoop(ListNode head1,ListNode entryNodeOfLoop1,ListNode head2,ListNode entryNodeOfLoop2){
//已知入环结点entryNodeOfLoop1,entryNodeOfLoop2
//先判断入环结点是否相同
if(entryNodeOfLoop1==entryNodeOfLoop2){
//在入环结点之前部分的直线链表上面找相交点,即在head到entryNodeOfLoop1结点之间找相交结点
return this.intersectionNodeWithoutLoop(head1,head2,entryNodeOfLoop1);
}else{
//在环里面找相交点
//记住当前链表2的入环结点
ListNode p=entryNodeOfLoop2;
p=p.next;
while(p!=entryNodeOfLoop2){
if(p==entryNodeOfLoop1) return p;
p=p.next;
}
return null;
}
}
}