链表查找环入口(使用快慢指针)

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null || head.next == null)return null;
        ListNode slow = head;
        ListNode fast = head;
        boolean flag = false;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                flag = true;
                break;
            }
        }
        if(!flag) return null;
        slow = head;
        while(slow != fast){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

使用快慢指针的方法,,,我数学比较差理解了比较长 的时间,我自己总结一下逻辑

定义快慢指针,快指针每次走两步,慢指针每次一步

通过while遍历两个指针会相遇,相遇点在环的某一个位置

然后开始论证下一个结论:慢指针重新从head开始向后逐个遍历,快指针同步逐个在相遇点遍历,最终一定会在入口相遇

设:环外长度m,环长度n,相遇点距离入口k,快指针走了S圈

慢指针移动距离:m+k

快指针移动距离:(m+sn)+k

快是慢的两倍

2(m+k)=m+sn+k

两指针相遇了,则快指针走几圈无关紧要,让圈数等于1;

化简后m=n-k

这个结果意味着外环长度就等于相遇点到入口的距离,所以再从相遇点以及head开始同步移动,一定会在入口相遇。

(这属实是数学推导问题了,我不太行)

然后,我又找到了一个Java通过Set的唯一特性实现了更简单的方法。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null || head.next == null)return null;
        ListNode link = head;
        Set<ListNode> haslist = new HashSet<>();
        while(head.next != null){
            if(!haslist.add(link)){
                return link;
            }else{
                link = link.next;
            }
        }
        return null;
    }
}

只需要遍历一次

 

 虽然简单了,但是效率低了

posted @ 2021-08-25 10:46  K峰  Views(239)  Comments(0)    收藏  举报