链表查找环入口(使用快慢指针)
/** * 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; } }
只需要遍历一次

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

浙公网安备 33010602011771号