慢指针slowPtr每次后移1个结点。快指针fastPtr每次后移2个结点
function isLinkedListContainsLoop( head){ if(head==null){ return false; } let slowPtr=head; let fastPtr=head; while(slowPtr.next!=null && fastPtr.next.next!=null){ slowPtr=slowPtr.next; fastPtr=fastPtr.next.next; if(slowPtr==fastPtr){ return true; } } return false; }
衍生问题1------找出环的入口点(起点)
当fast按照每次2步,slow每次一步的方式走,发现fastPtr和slowPtr重合,确定了单向链表有环路。接下来,让slowPrt回到链表的头部,然后slowPtr和fastPtr各自从自己的位置(fastPtr从两个指针相遇的位置position出发)沿着链表出发,每次步长1,那么当fastPtr和slowPtr再次相遇的时候,就是环路的入口了。
function findLinkedListLoopBegin(head) { if (head == null) { return null; } let slowPtr = head; let fastPtr = head; let isLinkedListContainsLoop = false; while (slowPtr.next != null && fastPtr.next.next != null) { slowPtr = slowPtr.next; fastPtr = fastPtr.next.next; if (slowPtr == fastPtr) { isLinkedListContainsLoop = true; break; } } if (isLinkedListContainsLoop) { slowPtr = head; let count = 1 while (slowPtr == fastPtr) { slowPtr = slowPtr.next; fastPtr = fastPtr.next; count++ } return slowPtr; } return null; }
设环长为n,非环形部分长度为m,当第一次相遇时显然slow指针行走了 m+An+k(A表示slow行走了A圈。附:An 是因为如果环够大,则他们的相遇需要经过好几环才相遇)。fast行走了 m+B*n+k。
上面我们说了slow每次行走一步,fast每次行走两步,则在同一时间,fast行走的路程是slow的两倍。假设slow行走的路程为S,则fast行走的路程为2S。
用fast减去slow可得:
S=(B-A)*n
很显然这意味着当slow和fast相遇时他们走过的路程都为圈长的倍数。
接下来,将slow移动到起点位置,如下图:
然后每次两个指针都只移动一步,当slow移动了m,即到达了环的起点位置,此时fast总共移动了 2S+m。 考虑到S为环长的倍数,可以理解为:fast先从链表起点出发,经过了m到达环的起点,然后绕着环移动了几圈,最终又到达环的起点,值为2S+m。所以fast最终必定处在环的起点位置。即两者相遇点即为环的起点位置。
衍生问题2,求环的大小(长度)
当fast按照每次2步,slow每次一步的方式走,发现fastPtr和slowPtr重合,确定了单向链表有环路。接下来,让slowPrt不动,fast 绕着环移动,每次移动一步,计数count加1,当两指针再次相遇时,count即是环的大小
回归原题,也是用快慢节点
function circularArrayLoop(nums) { let n = nums.length; if (n <= 1) { return false } function getNext(i) { return (i + nums[i] + n) % n } for (let i = 0; i < n; i++) { let slow = i, fast = getNext(i); //确保总是朝着一个方向前进 while (nums[slow] * nums[i] > 0 && nums[fast] * nums[i] > 0) { if (slow == fast) { //判断是否只有一个元素 if (slow == getNext(slow)) { break; } return true; } slow = getNext(slow); fast = getNext(fast);//快指针每次走两步 if (nums[fast] * nums[i] < 0) {//如果方向反了 break; } fast = getNext(fast); } } return false; } console.log(circularArrayLoop([2, -1, 1, 2, 2])) console.log(circularArrayLoop([-1, 2])) console.log(circularArrayLoop([-2, 1, -1, -2, -2]))
来源:https://www.cnblogs.com/rubylouvre/p/12159239.html