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

  

分类:

技术点:

相关文章: