两个单链表相交的一系列问题

【题目】 在本题中,单链表可能有环,也可能无环。给定两个 单链表的头节点 head1和head2,这两个链表可能相交,也可能 不相交。请实现一个函数, 如果两个链表相交,请返回相交的 第一个节点;如果不相交,返回null 即可。 要求:如果链表1 的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外 空间复杂度请达到O(1)。
将题目拆分:

  1. 判断链表是否有环,有环则返回第一个换节点
  2. 判断两个无环链表是否相交,相交则返回第一个节点
  3. 判断两个有环链表是否相交,相交则返回第一个节点
    一个链表有环,一个链表无环是不可能相交的
    判断链表是否有环,有环则返回第一个换节点
    设置一个快指针,和一个慢指针,快指针每次走两个,慢指针每次走一个。当快指针与慢指针相遇。将快指针重新设置为头节点,然后快指针和慢指针同时每次都走一个,当再次相遇时,此时的位置便是第一个环节点位置。

判断是否有环的代码:

public static Node getLoopNode(Node head){
        if (head==null||head.next==null||head.next.next==null){
            return null;
        }
        Node n1=head.next;//慢指针
        Node n2=head.next.next;//快指针
        while (n1!=n2){
            if (n2.next==null||n2.next.next==null){
                return null;
            }
            n2=n2.next.next;
            n1=n1.next;
        }
        n2=head;//将n2设置为头重新遍历
        while (n1!=n2){
            n1=n1.next;
            n2=n2.next;
        }
        return n1;
    }

判断两个无环链表是否相交,相交则返回第一个节点:
可以将两个链表先进行遍历,得到两个链表的长度,假设第一的链表长度为100,第二个链表长度为80,那么可以先让链表一走二十个,然后两个一起走,当两个第一次相遇时,该位置即为两个链表相交的第一个节点。
判断两个无环链表是否相交:

 public static Node noLoop(Node head1,Node head2){
        if (head1==null&&head2==null){
            return null;
        }
        Node cur1=head1;
        Node cur2=head2;
        int n=0;
        while (cur1!=null){
            n++;
            cur1=cur1.next;
        }
        while (cur2!=null){
            n--;
            cur2=cur2.next;
        }
        cur1=n>0?head1:head2;
        cur2=cur1==head1?head2:head1;
        n=Math.abs(n);
        while (n!=0){
            n--;
            cur1=cur1.next;
        }
        while (cur1!=cur2){
            cur1=cur1.next;
            cur2=cur2.next;
        }
        return cur1;
    }

判断两个有环链表是否相交,相交则返回第一个节点:
先找到两个链表的各自环节点(通过getLoopNode方法), 然后让第一个环的环节点,继续向下遍历,当遇到第二个链表的环节点时,说明两个有环链表相交,此时返回第一个链表的环节点就可以了。
判断两个有环链表是否相交代码:

public static Node bothLoop(Node head1,Node loop1,Node head2,Node loop2){
        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=n>0?head1:head2;
            cur2=cur1==head1?head2:head1;
            n=Math.abs(n);
            while (n!=0){
                n--;
                cur1=cur1.next;
            }
            while (cur1!=cur2){
                cur1=cur1.next;
                cur2=cur2.next;
            }
            return cur1;
        }else {
            cur1=loop1.next;
            while (cur1!=loop1){
                if (cur1==loop2){
                    return loop1;
                }
                cur1=cur1.next;
            }
            return null;
        }
    }

完整代码:

package basic_class_03;

/**
 * 类名:Code_14_FindFirstIntersectNode<br>
 * 功能:两个单列表相交一系列问题<br>
 * 作者:java战士<br>
 * 日期:2019/9/4<br>
 * 版本:v1.0.0
 * 历史修订:
 */
public class Code_14_FindFirstIntersectNode {
    public static class Node{
        public int data;
        public Node next;

        public Node(int data) {
            this.data = data;
        }
    }

    public static Node getIntersectNode(Node head1,Node head2){
        if (head1==null||head2==null){
            return null;
        }
        Node loop1=getLoopNode(head1);
        Node loop2=getLoopNode(head2);
        if (loop1!=null&&loop2!=null){
            return bothLoop(head1,loop1,head2,loop2);
        }else if (loop1==null&&loop2==null){
            return noLoop(head1,head2);
        }else {
            return null;
        }
    }
    public static Node getLoopNode(Node head){
        if (head==null||head.next==null||head.next.next==null){
            return null;
        }
        Node n1=head.next;//慢指针
        Node n2=head.next.next;//快指针
        while (n1!=n2){
            if (n2.next==null||n2.next.next==null){
                return null;
            }
            n2=n2.next.next;
            n1=n1.next;
        }
        n2=head;//将n2设置为头重新遍历
        while (n1!=n2){
            n1=n1.next;
            n2=n2.next;
        }
        return n1;
    }
    //没有环的时候
    public static Node noLoop(Node head1,Node head2){
        if (head1==null&&head2==null){
            return null;
        }
        Node cur1=head1;
        Node cur2=head2;
        int n=0;
        while (cur1!=null){
            n++;
            cur1=cur1.next;
        }
        while (cur2!=null){
            n--;
            cur2=cur2.next;
        }
        cur1=n>0?head1:head2;
        cur2=cur1==head1?head2:head1;
        n=Math.abs(n);
        while (n!=0){
            n--;
            cur1=cur1.next;
        }
        while (cur1!=cur2){
            cur1=cur1.next;
            cur2=cur2.next;
        }
        return cur1;
    }
    //有两个环的时候
    public static Node bothLoop(Node head1,Node loop1,Node head2,Node loop2){
        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=n>0?head1:head2;
            cur2=cur1==head1?head2:head1;
            n=Math.abs(n);
            while (n!=0){
                n--;
                cur1=cur1.next;
            }
            while (cur1!=cur2){
                cur1=cur1.next;
                cur2=cur2.next;
            }
            return cur1;
        }else {
            cur1=loop1.next;
            while (cur1!=loop1){
                if (cur1==loop2){
                    return loop1;
                }
                cur1=cur1.next;
            }
            return null;
        }
    }
    public static void main(String[] args){
        //1,2,3,4,5,6,7,null
        Node head1=new Node(1);
        head1.next=new Node(2);
        head1.next.next=new Node(3);
        head1.next.next.next=new Node(4);
        head1.next.next.next.next=new Node(5);
        head1.next.next.next.next.next=new Node(6);
        head1.next.next.next.next.next.next=new Node(7);

        //0,9,8,6,7,null
        Node head2=new Node(0);
        head2.next=new Node(9);
        head2.next.next=new Node(8);
        head2.next.next.next=head1.next.next.next.next.next;//8--->7
        System.out.println(getIntersectNode(head1,head2).data);

        //1,2,3,4,5,6,7,3....
        head1=new Node(1);
        head1.next=new Node(2);
        head1.next.next=new Node(3);
        head1.next.next.next=new Node(4);
        head1.next.next.next.next=new Node(5);
        head1.next.next.next.next.next=new Node(6);
        head1.next.next.next.next.next.next=new Node(7);
        head1.next.next.next.next.next.next=head1.next.next;//7--->3
        //0,9,8,3....
        head2=new Node(0);
        head2.next=new Node(9);
        head2.next.next=new Node(8);
        head2.next.next.next=head1.next.next;//8--->3
        System.out.println(getIntersectNode(head1,head2).data);

        head2=new Node(0);
        head2.next=new Node(9);
        head2.next.next=new Node(8);
        head2.next.next.next=head1.next.next.next;//8---4
        System.out.println(getIntersectNode(head1,head2).data);
    }
}

测试结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值