判断两个链表是否相交并找出交点

一个比较经典的问题,判断两个链表是否相交,如果相交找出他们的交点。

image

思路:

1、碰到这个问题,第一印象是采用hash来判断,将两个链表的节点进行hash,然后判断出节点,这种想法当然是可以的。

2、当然采用暴力的方法也是可以的,遍历两个链表,在遍历的过程中进行比较,看节点是否相同。

3、第三种思路是比较奇特的,在编程之美上看到的。先遍历第一个链表到他的尾部,然后将尾部的next指针指向第二个链表(尾部指针的next本来指向的是null)。这样两个链表就合成了一个链表,判断原来的两个链表是否相交也就转变成了判断新的链表是否有环的问题了:即判断单链表是否有环?

这样进行转换后就可以从链表头部进行判断了,其实并不用。通过简单的了解我们就很容易知道,如果新链表是有环的,那么原来第二个链表的头部一定在环上。因此我们就可以从第二个链表的头部进行遍历的,从而减少了时间复杂度(减少的时间复杂度是第一个链表的长度)。

下图是一个简单的演示:

image

这种方法可以判断两个链表是否相交,但不太容易找出他们的交点。

4、仔细研究两个链表,如果他们相交的话,那么他们最后的一个节点一定是相同的,否则是不相交的。因此判断两个链表是否相交就很简单了,分别遍历到两个链表的尾部,然后判断他们是否相同,如果相同,则相交;否则不相交。示意图如下:

image

判断出两个链表相交后就是判断他们的交点了。假设第一个链表长度为len1,第二个问len2,然后找出长度较长的,让长度较长的链表指针向后移动|len1 - len2| (len1-len2的绝对值),然后在开始遍历两个链表,判断节点是否相同即可。

//单链表的节点
class Node<T extends Comparable<T>> implements Comparable<Node<T>>{
private T data;
private Node<T> next;

public Node(){

}
public Node(T data){
this.data=data;
this.next=null;
}



public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Node<T> getNext() {
return next;
}
public void setNext(Node<T> next) {
this.next = next;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
return result;
}


@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
return true;
}
@Override
public int compareTo(Node<T> o) {
return this.data.compareTo(o.getData());
}
}


 
//  判断两个单链表是否相交
//如果单纯的判断是否相交,只需要看最后一个指针是否相等
/*
 * 一共有二中解法
 * 第一种:将二个链表连接起来,查看链表2是否存在环。如果存在环,则第一个入口点就是相交的点
 * 
 * */
//单链表是没有环的
/*
 * 二个链表相交的性质
 * (1)一旦两个链表相交,那么两个链表中的节点一定有相同地址。


            (2)一旦两个链表相交,那么两个链表从相交节点开始到尾节点一定都是相同的节点。
 * 解题思路
 * 先遍历第一个链表到他的尾部,然后将尾部的next指针指向第二个链表(尾部指针的next本来指向的是null)。
 * 这样两个链表就合成了一个链表,判断原来的两个链表是否相交也就转变成了判断新的链表是否有环的问题了:即判断单链表是否有环
 * */
   public Node<T> isIntersectByConnect(Node<T> head1,Node<T> head2){
    //得到当前链表的最后一个节点
    Node<T> target=null;
    if(head1!=null){
    while(head1.getNext()!=null){
    head1=head1.getNext();
    }
    head1.setNext(head2);
    target=head1;
     }else if(head2!=null){
     while(head2.getNext()!=null){
     head2=head2.getNext();
     }
     head2.setNext(head1);
     target=head2;
     }
    return this.FindLoopPort(head2);
   }
 
   public  Node<T> isIntersect(Node<T> head1,Node<T> head2){  
       Node<T> target=null;  
       if(head1==null||head2==null)return target;  
       boolean pos1=this.hasCycle(head1);
       boolean pos2=this.hasCycle(head2);
       // 一个链表有环,另一个链表没环,那肯定没有交点  
       if(pos1==false&&pos2==true||pos1==false&&pos2==true)return null;
       int len1=this.size(head1);  
       int len2=this.size(head2);  
       if(len1>=len2){  
           for(int i=0;i<len1-len2;i++){  
               head1=head1.getNext();  
           }  
       }else{  
           for(int i=0;i<len2-len1;i++){  
               head2=head2.getNext();  
           }  
       }  
       while(head1!=null&&head2!=null){  
           if(head1.equals(head2)){  
               target=head1;  
               break;  
           }  
           else{  
               head1=head1.getNext();  
               head2=head2.getNext();  
           }  
       }  
       return target;
      }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值