zoukankan      html  css  js  c++  java
  • 链表--两个单链表相交的一系列问题

     在本题中, 单链表可能有环, 也可能无环。 给定两个单链表的头节点 head1和head2,这两个链表可能相交, 也可能不相交。

    请实现一个函数, 如果两个链表相交, 请返回相交的第一个节点; 如果不相交, 返回null 即可。

    要求: 如果链表1的长度为N, 链表2的长度为M, 时间复杂度请达到 O(N+M), 额外空间复杂度请达到O(1)。

    问题1:判断链表是否有环,并返回环的第一个结点:

    快慢指针,快指针一次走两步,慢指针一次走一步,当快指针重新追上慢指针的时候,快指针指向链表头部,然后变身为慢指针(一次走一步)

    当快指针与慢指针再次相遇时,即为环的第一个结点。

     问题2:当两个链表都无环时:

    问题退化为求两个无环链表的第一个公共结点的问题(根据链表的特殊性,只有一个next指针,只能连接一个下一个结点,所以第一个公共结点之后,只知道链表的结尾都是相同的),剑指offer上出现过剑指offer——两个链表的第一个公共结点

    法1)遍历两个链表,得出两个链表的长度len1, len2,然后在较长的链表上先走len1 - len2个结点,然后在一起走,并且比较,相同返回该结点即可

    法2)将链表1,2均压栈stack1, stack2,然后依次弹出,直到遇到不同的结点,此时上一个结点就是第一个公共结点,若有一个栈为空,则两个链表不相交

    问题3:当两个链表一个有环一个无环时:

    可以得出结论就是这两个链表不相交,因为链表的特性决定了如果两个链表相交的话,它们之后会一直相交下去,无环的和有环的链表不能公共的结点,相矛盾。直接返回null即可

    问题4:当两个链表均有环时:环入口是loop1,loop2

    情况一:两个链表不相交    loop1 != loop2

    此时,遍历两个链表,当其中某一个链表再次回到 loop 时,则确定两个链表不相交

    node从环的下一个结点开始遍历,当

    node1 == loop1 || node2 == loop2时,此时无相交

    情况二:两个链表在同一节点相交

    此种情况下,两个链表的环入口肯定是相同的  loop1 == loop2

     或者是

    情况三:两个链表在不同节点相交 loop1 != loop2

    此时,从环的下一个结点开始遍历,当node1 == loop1 || node2 == loop2时 即证明相交

     

    public static class Node{
            public int val;
            public Node next = null;
    
            public Node(int val){
                this.val = val;
            }
        }
    
        public static Node findFirstNodeFromLoop(Node head){
            if(head == null || head.next == null) return null;
            Node fast = head;
            Node slow = head;
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
                if(slow == fast) break;
            }
            if(fast == null || fast.next == null){
                return null;
            }
            fast = head;
            while(fast != slow){
                fast = fast.next;
                slow = slow.next;
            }
            return fast;
        }
    
        //有环,且入环第一个结点不同
        //1.两个有环链表不相交
        //2.两个有环链表相交,但是相交结点不同
        public static Node findFirstCommonNodeWithLoop(Node loop1, Node loop2){
            if(loop1 == null || loop2 == null) return null;
    
            Node node1 = loop1.next;
            Node node2 = loop2.next;
            while(node1 != loop1 || node2 != loop2){
                System.out.println(node1.val + " " + node2.val);
                if(node1 == loop2 || node2 == loop1) return node1;
                node1 = node1.next;
                node2 = node2.next;
    
    
            }
    
            return new Node(1000000);
        }
    
        //无环,找第一个公共结点
        //有环,且入环第一个结点相同
        //正确
        public static Node findFirstCommonNodeWithoutLoop(Node head1, Node head2){
            if(head1 == null || head2 == null) return null;
            int len1 = 0;
            int len2 = 0;
            Node node1 = head1;
            Node node2 = head2;
            while(node1 != null){
                node1 = node1.next;
                len1++;
            }
            while(node2 != null){
                node2 = node2.next;
                len2++;
            }
    
            node1 = len1 > len2 ? head1 : head2;
            node2 = len1 > len2 ? head2 : head1;
            for(int i = 0; i < Math.abs(len1 - len2); i++){
                node1 = node1.next;
            }
    
            while(node1 != null && node2 != null){
                if(node1 == node2) return node1;
                node1 = node1.next;
                node2 = node2.next;
            }
            return null;
        }
    

      

    测试函数

    /**
         * head1,head2为两个链表均有环,且第一个相交结点不同
         * head3,head4为两个链表均有环,且无相交结点
         * head5,head6为两个链表均有环,且第一个相交结点相同
         * @param args
         */
        public static void main(String[] args){
            Node head1 = new Node(0);
            Node head2 = new Node(0);
            Node node1 = head1;
            Node node2 = head2;
    
            node1.next = new Node(1);
            node1 = node1.next;
            node1.next = new Node(2);
            node1 = node1.next;
            node1.next = new Node(3);
            node1 = node1.next;
            node1.next = new Node(4);
            node1 = node1.next;
            node1.next = new Node(5);
            node1 = node1.next;
            node1.next = new Node(6);
            node1 = node1.next;
            node1.next = new Node(7);
            node1 = node1.next;
            node1.next = new Node(8);
            node1 = node1.next;
            node1.next = new Node(9);
            node1 = node1.next;
            node1.next = head1.next.next.next.next; //4为环入口
    
    
            node2.next = new Node(11);
            node2 = node2.next;
            node2.next = new Node(12);
            node2 = node2.next;
            node2.next = new Node(13);
            node2 = node2.next;
            node2.next = new Node(14);
            node2 = node2.next;
            node2.next = new Node(15);
            node2 = node2.next;
            node2.next = new Node(16);
            node2 = node2.next;
            node2.next = head1.next.next.next.next.next.next;//6为环入口
    
            Node head3 = new Node(0);
            Node head4 = new Node(0);
    
            node1 = head3;
            node2 = head4;
    
            node1.next = new Node(1);
            node1 = node1.next;
            node1.next = new Node(2);
            node1 = node1.next;
            node1.next = new Node(3);
            node1 = node1.next;
            node1.next = new Node(4);
            node1 = node1.next;
            node1.next = new Node(5);
            node1 = node1.next;
            node1.next = new Node(6);
            node1 = node1.next;
            node1.next = new Node(7);
            node1 = node1.next;
            node1.next = new Node(8);
            node1 = node1.next;
            node1.next = new Node(9);
            node1 = node1.next;
            node1.next = head3.next.next.next.next; //4为环入口
    
    
            node2.next = new Node(11);
            node2 = node2.next;
            node2.next = new Node(12);
            node2 = node2.next;
            node2.next = new Node(13);
            node2 = node2.next;
            node2.next = new Node(14);
            node2 = node2.next;
            node2.next = new Node(15);
            node2 = node2.next;
            node2.next = new Node(16);
            node2 = node2.next;
    
            node2.next = head4.next.next.next;//14为环入口
            
            Node head5 = new Node(0);
            Node head6 = new Node(0);
    
            node1 = head5;
            node2 = head6;
    
            node1.next = new Node(1);
            node1 = node1.next;
            node1.next = new Node(2);
            node1 = node1.next;
            node1.next = new Node(3);
            node1 = node1.next;
            node1.next = new Node(4);
            node1 = node1.next;
            node1.next = new Node(5);
            node1 = node1.next;
            node1.next = new Node(6);
            node1 = node1.next;
            node1.next = new Node(7);
            node1 = node1.next;
            node1.next = new Node(8);
            node1 = node1.next;
            node1.next = new Node(9);
            node1 = node1.next;
            node1.next = head5.next.next.next.next; //4为环入口
    
    
            node2.next = new Node(11);
            node2 = node2.next;
            node2.next = new Node(12);
            node2 = node2.next;
            node2.next = new Node(13);
            node2 = node2.next;
            node2.next = new Node(14);
            node2 = node2.next;
            node2.next = new Node(15);
            node2 = node2.next;
            node2.next = new Node(16);
            node2 = node2.next;
    
            node2.next = head5.next;//4为环入口   1为公共结点
    
            /**
             * head1,head2为两个链表均有环,且第一个相交结点不同
             * head3,head4为两个链表均有环,且无相交结点
             * head5,head6为两个链表均有环,且第一个相交结点相同
             *
             */
            Node node = null;
            node1 = head3;
            node2 = head4;
            Node loop1 = findFirstNodeFromLoop( head3 );
            Node loop2 = findFirstNodeFromLoop(head4);
            System.out.println(loop1.val);
            System.out.println(loop2.val);
            //两个链表均无环
            if(loop1 == null && loop2 == null){
                node = findFirstCommonNodeWithoutLoop(node1, node2);
            } else if((loop1 == null && loop2 != null) || (loop1 != null && loop2 == null)){
                node = null;
            } else if(loop1 == loop2){
                //两个链表有相交的结点
    
                while(node1.next != loop1){
                    node1 = node1.next;
                }
                System.out.println(node1.val);
                node1.next = null;
                node = findFirstCommonNodeWithoutLoop( head5, head6 );
    
                node1.next = loop1;
    
            } else {
                node = findFirstCommonNodeWithLoop(loop1, loop2);
                //loop1 != loop2  1.两个链表无相交结点  2.两个链表相交结点不同
            }
            String str = node.val == 1000000 ? "无相同结点 " : "有相同结点 ";
            System.out.println(str + node.val);
        }
    

      

  • 相关阅读:
    vue自定义指令
    ZOJ Problem Set–2104 Let the Balloon Rise
    ZOJ Problem Set 3202 Secondprice Auction
    ZOJ Problem Set–1879 Jolly Jumpers
    ZOJ Problem Set–2405 Specialized FourDigit Numbers
    ZOJ Problem Set–1874 Primary Arithmetic
    ZOJ Problem Set–1970 All in All
    ZOJ Problem Set–1828 Fibonacci Numbers
    要怎么样调整状态呢
    ZOJ Problem Set–1951 Goldbach's Conjecture
  • 原文地址:https://www.cnblogs.com/SkyeAngel/p/8761084.html
Copyright © 2011-2022 走看看