题目要求

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up:
Can you solve it without using extra space?

这道题目要求判断一个链表中是否有环,如果有环,就返回环中的第一个节点。

判断是否有环

判断是否有环有两种方法,第一种是双指针的方法,双指针方法意味着快指针一定有一天会遇上慢指针,只要链表中有环。

    public boolean hasCycle(ListNode head) {
        if(head==null) return false;
        ListNode walker = head, runner = head;
        while(runner.next!=null && runner.next.next!=null){
            walker = walker.next;
            runner = runner.next.next;
            if(walker==runner) return true;
        }
        return false;
    }

还有一种方法是指将链表的结果给拆掉,一旦遍历过当前节点,就将当前节点的下一个指针指向dummy节点。如果有环,就会重复遇到这个指向dummy的节点。则该链表有环,且该节点就是环的起始节点。但是这个方法会毁坏原来链表的数据结构。

    public boolean hasCycle2(ListNode head){
        if(head==null) return false;
        ListNode dummy = new ListNode(0);
        while(head.next!=null){
            if(head.next==dummy)return true;
            ListNode temp = head.next;
            head.next = dummy;
            head = temp;
        }
        return false;
    }

找到环的起始节点

那么如何才能在环中找到起始节点呢?这就要找出双指针之间运动的规律了。当快慢指针第一次相遇时,我们假设慢指针和环中第一个节点距离为X,而环中第一个节点距离起始节点为Y。而因为快指针在走了一圈以后也停留在该节点,因此快指针走过的总距离为(X+Y)*2。又因为快慢指针相遇决定了快指针比慢指针多走了一圈,因此2(X+Y)-(X+Y)=CYCLE,也就是X+Y=CYCLE这时我们可以知道如果再走Y步,慢指针就可以回到环中的第一个节点,而Y也恰好是环中第一个节点距离起始节点的位置。因此如果这时有另一个指针同时从起点出发,则二者相遇的地方就是环的起始节点。

    public ListNode detectCycle(ListNode head) {
        if(head==null) return null;
        ListNode runner = head, walker = head;
        while(runner.next!=null && runner.next.next!=null){
            walker = walker.next;
            runner = runner.next.next;
            if(walker==runner){
                ListNode temp = head;
                while(temp!=walker){
                    temp = temp.next;
                    walker = walker.next;
                }
                return temp;
            }
        }
        
        return null;
    }

clipboard.png
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注我的微信公众号!将会不定期的发放福利哦~


raledong
2.7k 声望2k 粉丝

心怀远方,负重前行