返回两个链表相交的节点

问题

给定两个链表(可能有环,也可能无环),返回两个链表相交的节点,如果不相交返回null,如果相交多个返回其中一个。

分析

因为这两个链表可能有环也可能无环,有以下几种情况

  • 1、链表A无环,链表B无环
  • 2、链表A有环,链表B有环
  • 3、链表A有环,链表B无环
  • 4、链表A无环,链表B有环
    第三,四种情况不可能相交,也就不再考虑。
    因此两个链表要么都是无环,要么都是有环。

获取有环链表第一个入环节点

下面的操作首先获取的就是有环链表第一个入环节点,如果无环,返回null

public Node getLoopNode(Node head){
    
    
    if(head==null||head.next==null||head.next.next==null){
    
    
        return null;
    }
    // slow fast point
    Node slow = head.next;
    Node fast = head.next.next;
    while(slow!=fast){
    
    
        if(slow.next==null||fast.next.next==null){
    
    
            return null;
        }
        slow = slow.next;
        fast = fast.next.next;
    }
    // 快指针重新回到head,每次走一步
    fast = head;
    while(fast!=slow){
    
    
        slow = slow.next;
        fast = fast.next;
    }
    return slow;
}

无环情况下

无环情况下又分为相交和不相交。那怎样判断两者相交还是不相交?
相交一定有公共部分,因为两者无环,所以遍历到最后的节点是一样的,如果不一样,说明不想交,直接返回null;如果相交,需要找出这两条链表哪条较长,先让长链表走n步,n是两个链表长度的差值,然后两个链表依次向前遍历,直到两个链表指向同一个节点,返回即可。

代码实现:

// 如果两个链表都没环,返回第一个相交节点,不相交返回null
public static Node noLoop(Node head1,Node head2){
    
    
    if(head1==null||head2==null){
    
    
        return null;
    }
    Node cur1=null;
    Node cur2 = null;
    int n=0;
    while(cur1.next!=null){
    
    
        n++;
        cur1=cur1.next;
    }
     while(cur2!=loop2){
    
    
        n--;
        cur2=cur2.next;
     }
    // 不相交
    if(cur1!=cur2){
    
    
        return null;
    }
    //cur1 指向长链表
    //cur2指向短链表
    cur1 = n>0?head1:head2;
    cur2=cur1==head1?head2:head1;
    n=Math.abs(n);
    //长链表先走n步
    while(n!=0){
    
    
         n--;
         cur1=cur1.next;
     }
     //然后长短链表的长度一致后同时往后遍历,如果相等代表第二种情况:两个有环链表相交一个点
     while(cur1!=cur2){
    
    
         cur1 = cur1.next;
         cur2=cur2.next;
      }
        return cur1;
}

有环情况下

有环的时候有三种情况

  1. 两个链表是独立的不相交。
  2. 两个链表相交一个节点(共用一个环)
  3. 两个链表相交两个节点(共用一个环)
public static Node bothLoop(Node head1,Node loop1,Node head2,Node loo2){
    
    
    Node cur1 = null;
    Node cur2 = null;
    //如果两个链表第一个入环节点一致代表两个有环节点相交于一点
    if(loop1==loop2){
    
    
        cur1 = head1;
        cur2 = head2;
        int n=0;
        while(cur1!=loop1){
    
    
            n++;
            cur1=cur1.next;
        }
        while(cur2!=loop2){
    
    
            n--;
            cur2=cur2.next;
        }
        //cur1 指向长链表
        //cur2指向短链表
        cur1 = n>0?head1:head2;
        cur2=cur1==head1?head2:head1;
        n=Math.abs(n);
        //长链表先走n步
        while(n!=0){
    
    
            n--;
            cur1=cur1.next;
        }
        //然后长短链表的长度一致后同时往后遍历,如果相等代表第二种情况:两个有环链表相交一个点
        while(cur1!=cur2){
    
    
            cur1 = cur1.next;
            cur2=cur2.next;
        }
        return cur1;
    }else{
    
    
        //第三种情况:两个有环链表相交与loop1 loop2
        // 从loop1开始向后遍历节点,如果遇到loop2代表是第三种情况
        cur1 = loop1.next;
        while(cur1!=loop1){
    
    
            if(cur1==loop2){
    
    
                return loop2;
            }
            cur1=cur1.next;
        }
        //没有遇到代表两个有环链表没相交,返回null
        return null;
    }
}

总代码

如果一上来两个链表都为null,直接返回null;
获取链表A的第一个入环节点
获取B的第一个入环节点
如果入环节点都是null代表是两个链表是无环的,如果两个链表的第一个入环节点都不为空,表示两个链表都是有环的,采用有环的情况处理。其他情况是第三第四种不相交,直接返回null。

public static Node getIntersectNode(Node head1,Node head2){
    
    
    if(head1==null||head2==null) return null;
    // 返回链表1的第一个入环节点
    Node loop1 = getLoopNode(head1);
      // 返回链表2的第一个入环节点
    Node loop2 = getLoopNode(head2);
    if(loop1==null&&loop2==null){
    
    
        //两个链表是无环的相交
        return noLoop(head1,head2);
    }
    if(loo1!=null&&loop2!=null){
    
    
        //有环链表相交
        return bothLoop(head1,loop1,head2,loop2);
    }
    //不相交
    return null;
    
}

おすすめ

転載: blog.csdn.net/qq_43672652/article/details/113820143