判断两条单链表是否相交返回相交节点

题目:

        给两个链表,两个链表相交就返回相交的节点,如果不想交就为null

        给两个head节点

        需要时间复杂度O(n) 空间O(1)

简单方案:容器的办法  HashSet  循环第一个链表的所有链  循环第二个链表如果判定在set里面就说明有交点

两个链表相交情况图 不会有其他情况的! 单链表

复杂方案:

        1 先写一个函数1,可以判断单个链表是否有环

                 快慢指针:1 快指针一次走2步 慢指针一次走1步

                                快指针走到空说明无环节点 直接返回null

                                快慢指针相交说明有环

                                2 然后慢指针不动 ,快指针回到头结点,每次走一步

                                慢指针每次走一步,他俩相遇的继是环开始的节点

                                不要管证明,记住就完了

        2 主函数逻辑

                        1 先用 函数1 得到两个链表的入环节点loop1 和loop2

                        2 判断逻辑 如果loop1 和loop2 等于空 说明是图中1 或2的情况

                                        这个时候 只要循环两条链路走到根节点 并计数

                                        如果根节点是一个节点说明相交是图中情况2 根据计数可知道两 链表长度 ,长度相减 先让长链表走,然后两个链表一起走,第一个相交的就返回。

                                        如果跟节点不相交说明是图中情况1返回null

                        3 如果有环 说明是情况3,4,5

                                        1 先判断如果两个loop一样说明是4这种情况  切掉loop的下面环 就是情况2的样子,直接调用 之前写好的函数返回即可。

                                        2 如果两个loop不一样说明是情况4或者情况5

                                                这个时候 用任何loop 寻找next  如果最后碰到自己说明是3情况,如果碰到了另一个loop说明是情况5,返回任意loop即可

                        4 如果是2个链表 任意一个为空 另一个有环 那一定不相交 走完上面的逻辑只剩下这两种逻辑,直接返回null即可

代码:

package 算法;

/**
 * 			给两个链表,两个链表相交就返回相交的节点,如果不想交就为null
 * 			给两个head
 * 			需要时间复杂度O(n) 空间O(1)
 */
public class 两个链表相交问题 {
    //====实现代码===========================================
    //链表节点
    public static class Node{
        public Node next;
        public int num;
        public Node(int num) {
            this.num = num;
        }
    }

    /**
     * 输入两个链表的头 判断两个链表是否相交 如果相交 返回相交节点 如果不想交 返回空
     * @param head1
     * @param head2
     * @return
     */
    public static Node  intersectNode(Node head1 ,Node head2){
        if (head1 == null||head2==null) {
            return null;
        }
        //1 判断两条节点是否有环 有环输出入环节点
        Node loop1 = linkLoop(head1);
        Node loop2 = linkLoop(head2);
        //2 如果两个都没环说明 可能相交 使用 无环策略判断 Y 字形
        if (loop1 == null&&loop2==null) {
            return focusStrategy1(head1,head2);
        }
        // 3 如果两个都有环 用两个都有环的策略
        if (loop1 != null&&loop2!=null) {
            return focusStrategy2(head1,head2,loop1,loop2);
        }
        //判断 如果任何一个是有环 一个没还 则肯定不想交
        return null;
    }

    /**
     * 有环相交策略
     * @param head1
     * @param head2
     * @param loop1
     * @param loop2
     * @return
     */
    private static Node focusStrategy2(Node head1, Node head2, Node loop1, Node loop2) {

        // 1 第一种情况 如果两个相交节点相等 链表是Y 下面是0 形状的  切掉下面的0然后 按照五环策略返回
        if (loop1 == loop2) {
            loop1.next=null;
            return focusStrategy1(head1,head2);
        }
        // 2 这个时候 只剩 两种情况 如果 任何一个loop节点 循环向下找 找到的是另一个loop 那两个都是相交节点随便返回一个
        // 如果没找到说明是单独的两个66 链结构 返回空
        Node node = loop1.next;
        while (node!=loop2&&node!=loop1){
            node = node.next;
        }
        if (node == loop2) {
            return loop1;
        }
        return null;
    }

    /**
     * 无环相交策略
     * @param head1
     * @param head2
     * @return
     */
    private static Node focusStrategy1(Node head1, Node head2) {
        //循环两个 节点到根节点 如果 根节点 一样说明是Y字形 说明有相交 不一样直接返回空
        Node node1 = head1;
        Node node2 = head2;
        int n1=0;
        int n2=0;
        while (node1.next!=null){
            node1 = node1.next;
            n1++;
        }
        while (node2.next!=null){
            node2 = node2.next;
            n2++;
        }
        //不相等肯定不想交没交点
        if (node1 != node2) {
            return null;
        }
        //判断n1 和 n2 哪个大 大的先走步长 然后就一样大了 然后一起走 走到第一个相交的就是焦点
        node1 = head1;
        node2 = head2;
        if (n1 >n2) {
            n1 = n1-n2;
            while (n1!=0){
                n1--;
                node1 = node1.next;
            }
        }
        if (n1 <n2) {
            n2= n2-n1;
            while (n2!=0){
                n2--;
                node2 = node2.next;
            }
        }
        while (node1!=node2){
            node1 = node1.next;
            node2 = node2.next;
        }
        return node1;
    }

    /**
     * 给头节点确定有没有环 如果有就返回入环节点
     * @param head
     * @return
     */
    public static Node linkLoop(Node head){
        //快慢指针:1 快指针一次走2步 慢指针一次走1步
        //快指针走到空说明无环节点 直接返回null
        //快慢指针相交说明有环
        //2 然后慢指针不动 ,快指针回到头结点,每次走一步
        //慢指针每次走一步,他俩相遇的继是环开始的节点
        //不要管证明,记住就完了
        if (head.next == null||head.next.next == null) {
            return null;
        }
        Node slow = head.next;
        Node fist = head.next.next;
        while (fist!=null){
            //比较两个指针内存地址一不一样 一样说明有环
            if (fist==slow) {
                break;
            }
            slow = slow.next;
            if (fist.next != null&&fist.next.next!=null) {
                fist = fist.next.next;
            }else {
                fist =null;
            }
        }
        //如果快指针是null说明无环
        if (fist == null) {
            return null;
        }
        //有环就找入环节点
        fist = head;
        while (fist!=slow){
            slow = slow.next;
            fist = fist.next;
        }
        return fist;
    }
    //====实现代码===========================================

    //====对数器测试用代码===========================================

    /**
     * 图中情况1 链表test数据返回
     * @return
     */
    public static Node[]  testNode1(){
        Node[] nodes = new Node[2];

        Node head1 = new Node(1);
        Node node1 = new Node(2);
        Node node2 = new Node(3);
        head1.next=node1;
        node1.next=node2;

        Node head2 = new Node(4);
        Node node3 = new Node(5);
        Node node4 = new Node(6);
        head2.next=node3;
        node3.next=node4;

        nodes[0]=head1;
        nodes[1]=head2;

        return nodes;
    }


    /**
     * 图中情况2 链表test数据返回
     * @return
     */
    public static Node[]  testNode2(){
        Node[] nodes = new Node[2];

        Node head1 = new Node(1);
        Node node1 = new Node(2);
        Node node2 = new Node(3);
        head1.next=node1;
        node1.next=node2;

        Node head2 = new Node(4);
        Node node3 = new Node(5);
        Node node4 = new Node(6);
        head2.next=node3;
        node3.next=node4;

        //相交
        Node node5 = new Node(7);
        Node node6 = new Node(8);
        node2.next = node5;
        node4.next = node5;
        node5.next = node6;

        nodes[0]=head1;
        nodes[1]=head2;

        return nodes;
    }

    /**
     * 图中情况3 链表test数据返回
     * @return
     */
    public static Node[]  testNode3(){
        Node[] nodes = new Node[2];

        Node head1 = new Node(1);
        Node node1 = new Node(2);
        Node node2 = new Node(3);

        head1.next=node1;
        node1.next=node2;

        Node head2 = new Node(4);
        Node node3 = new Node(5);
        Node node4 = new Node(6);
        head2.next=node3;
        node3.next=node4;

        //制造环
        Node node7 = new Node(7);
        Node node8 = new Node(8);
        node2.next = node7;
        node7.next = node8;
        node8.next = node2;

        Node node9 = new Node(9);
        Node node10 = new Node(10);
        node4.next = node9;
        node9.next = node10;
        node10.next = node4;

        nodes[0]=head1;
        nodes[1]=head2;

        return nodes;
    }

    /**
     * 图中情况4 链表test数据返回
     * @return
     */
    public static Node[]  testNode4(){
        Node[] nodes = new Node[2];

        Node head1 = new Node(1);
        Node node1 = new Node(2);
        Node node2 = new Node(3);
        head1.next=node1;
        node1.next=node2;

        Node head2 = new Node(4);
        Node node3 = new Node(5);
        Node node4 = new Node(6);
        head2.next=node3;
        node3.next=node4;

        //相交
        Node node5 = new Node(7);
        Node node6 = new Node(8);
        node2.next = node5;
        node4.next = node5;
        node5.next = node6;

        //在加个环
        Node node9 = new Node(9);
        Node node10 = new Node(10);
        Node node11 = new Node(11);
        node6.next = node9;
        node9.next = node10;
        node10.next = node11;
        node11.next = node6;


        nodes[0]=head1;
        nodes[1]=head2;

        return nodes;
    }

    public static Node[]  testNode5(){
        Node[] nodes = new Node[2];

        Node head1 = new Node(1);
        Node node1 = new Node(2);
        Node node2 = new Node(3);
        head1.next=node1;
        node1.next=node2;

        Node head2 = new Node(4);
        Node node3 = new Node(5);
        Node node4 = new Node(6);
        head2.next=node3;
        node3.next=node4;

        Node node7 = new Node(7);
        Node node8 = new Node(8);
        Node node9 = new Node(9);
        Node node10 = new Node(10);

        node2.next = node7;
        node7.next = node4;
        node4.next = node8;
        node8.next =node9;
        node9.next = node10;
        node10.next = node2;



        nodes[0]=head1;
        nodes[1]=head2;

        return nodes;
    }


    //====对数器测试用代码===========================================

    public static void main(String[] args) {
        Node[] nodes1 =  testNode1();
        Node n1 = intersectNode(nodes1[0],nodes1[1]);
        if (n1 == null) {
            System.out.println("第一种情况测试成功");
        }else {
            System.out.println("第一种情况测试失败");
        }
        Node[] nodes2 =  testNode2();
        Node n2 = intersectNode(nodes2[0],nodes2[1]);
        if (n2.num == 7) {
            System.out.println("第二种情况测试成功");
        }else{
            System.out.println("第二种情况测试失败");
        }

        Node[] nodes3=  testNode3();
        Node n3 = intersectNode(nodes3[0],nodes3[1]);
        if (n3== null) {
            System.out.println("第三种情况测试成功");
        }else{
            System.out.println("第三种情况测试失败");
        }
        Node[] nodes4 =  testNode4();
        Node n4 = intersectNode(nodes4[0],nodes4[1]);
        if (n4.num == 7) {
            System.out.println("第四种情况测试成功");
        }else{
            System.out.println("第四种情况测试失败");
        }
        Node[] nodes5 =  testNode5();
        Node n5 = intersectNode(nodes5[0],nodes5[1]);
        if (n5.num == 3||n5.num == 6) {
            System.out.println("第五种情况测试成功");
        }else{
            System.out.println("第五种情况测试失败");
        }

    }

}

猜你喜欢

转载自blog.csdn.net/u010191034/article/details/121138345