判断两个单链表相交之前,我们应先判断单链表是否有环,然后就分成了有环链表的相交和无环链表的相交。
第一步:判断单链表是否有环,有就返回第一个入环节点。我们首先要有个清晰的认知就是,如果一个单链表有环,那么遍历链表就永远在环里转下去。对此我们有两种方法判断
第一种:利用hashset的特性,hashset的查询时间复杂度为O(1)。
public Node isHuan(Node head){//判断是否有环,若有环返回入环点(hashSet)
Node fistLoop=null;
HashSet<Node> set=new HashSet<>();
Node cur=head;
while (cur!=null){
if(!set.contains(cur)){//判断set中是否已经存储此节点,没有就存入,有就返回第一个入环节点
set.add(cur);
}else {
fistLoop=cur;
break;
}
cur=cur.next;
}
return fistLoop;
}
第二种:利用快慢指针
public Node isHuan1(Node head){//判断是否有环,若有环返回入环点(快慢指针)
if(head.next==null){
return head;
}
Node first=head.next.next;
Node slow=head.next;
while (first!=null &&first!=slow){
first=first.next.next;
slow=slow.next;
}
//当相等时,first指针指向头指针,并一步步前进,当快慢指针再次相等时,就是第一个入环节点,这个结论可由
//归纳法证明得知
if(first==slow){
first=head;
while (first!=slow){
first=first.next;
slow=slow.next;
if(first==slow){
break;
}
}
}
return first;
}
第二步,判断链表是否相交,注意链表相交会有相同的终点,单链表的一个节点指向必然是一个唯一的节点,所以两个链表交叉相交是不可能的
public Boolean intersect(Node head,Node head1){
Node first=isHuan1(head);
Node first1=isHuan(head1);
Boolean flag=false;
if(first==null && first1==null){//两个无环链表相交
if(Nointersect(head,head1)!=null){
flag=true;
}else {
flag=false;
}
}else if(first!=null && first1!=null){//两个有环链表相交
if(Loopintersect(head,head1,first,first1)!=null){
flag=true;
}else {
flag=false;
}
}else {//不可能相交,相交的单链表必有共同的终点
return flag;
}
return flag;
}
public Node Loopintersect(Node head,Node head1,Node first,Node first1){//两个有环链表相交
Node cur=head;
Node cur1=head1;
if(first==first1){
int n=0;
while (cur!=first){
n++;
cur=cur.next;
}
while (cur1!=first1){
n--;
cur1=cur1.next;
}
cur=n>0?head:head1;//较长的链表
cur1=n>0?head1:head;//较短的链表
int len=Math.abs(n);//两个链表的长度差值
while (len>0){
cur=cur.next;
len--;
}
while (cur!=cur1 &&cur!=first){
cur=cur.next;
cur1=cur1.next;
}
return cur;
}else{
cur=first.next;
while (cur!=first){
if(cur==first1){
return first;
}
cur=cur.next;
}
}
return null;
}
public Node Nointersect(Node head,Node head1){//两个无环链表相交
Node cur=head;
Node cur1=head1;
int n=0;
while (cur!=null){
n++;
cur=cur.next;
}
while (cur1!=null){
n--;
cur1=cur1.next;
}
cur=n>0?head:head1;//较长的链表
cur1=n>0?head1:head;//较短的链表
int len=Math.abs(n);//两个链表的长度差值
while (len>0){
cur=cur.next;
len--;
}
while (cur!=cur1 &&cur!=null){
cur=cur.next;
cur1=cur1.next;
}
return cur;
}