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


     在本题中, 单链表可能有环, 也可能无环。 给定两个单链表的头节点 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);
        }
    

      

  • 相关阅读:
    maven常用命令
    项目管理需要做的事情
    jinkins 部署过程
    怎么操作会导致MySQL锁表
    高性能Java代码的规范
    java8新特性(2)--接口的默认方法
    java8新特性1--Lambda表达式
    eclipse web项目
    js 0 "" null undefined
    Android分页加载
  • 原文地址:https://www.cnblogs.com/SkyeAngel/p/8761084.html
Copyright © 2020-2023  润新知