淺談雙指針技巧(一)---通過雙指針判斷鏈表成環問題

雙指針是算法中非常重要的一個解決問題的思路。
雙指針顧名思義,就是有兩個指針。根據雙指針的方向及速度,我們一般將雙指針分爲以下幾種場景
1、快慢雙指針
2、左右雙指針
所謂快慢雙指針是指,兩個指針,一個快指針,一個慢指針,按照相同的方向,從鏈表(或數組)的一側移動到另外一側的場景。

如下圖:

而左右雙指針,是指兩個指針,分別指向鏈表的左右兩側,相向而行。

如下圖:

 

1、快慢雙指針一般用於查找鏈表成環、特殊位置的節點、滑動窗口等問題。
2、左右雙指針一般是解決二分查找等問題

 

雖然都歸結爲雙指針,但其實他們的思想各不相同,甚至不同場景的問題,思想都不同,只是由於都用到了兩個指針,將這類算法技巧統稱爲雙指針。
本文我們重點來看快慢雙指針的經典問題:(防盜連接:本文首發自http://www.cnblogs.com/jilodream/ )
判斷鏈表是否成環
力扣 141. 環形鏈表 (https://leetcode.cn/problems/linked-list-cycle/)
給你一個鏈表的頭節點 head ,判斷鏈表中是否有環。
所謂的鏈表存在環,也就是下邊這個樣子,沒有某個節點的next指向null:

這個場景,如果環的結構不大的話,我們可以直接將結果直接存放到一張hash表中,然後指針從頭部依次遍歷,判斷新指向的節點是否已經存在於hash表中。

如果hash表中存在,則判定爲當前鏈表存在環,否則將該節點加入到hash表中,繼續遍歷。直到遇到鏈表的尾結點(next指針指向null)時,判定爲不存在環。
這種思想的代碼這裏就不寫了。(防盜連接:本文首發自http://www.cnblogs.com/jilodream/ )
如果數據規模小的話,這個辦法沒有問題,甚至會很快。但是如果數據規模很大的話,這就會導致沒有足夠的內存來存放這個hash表。
如果不採用臨時緩存的辦法,那麼應該咋麼解決呢?來看看快慢雙指針的思路
快指針Fast慢指針Low,同時指向頭結點,然後均向像隊尾移動,區別是快指針每次移動兩個節點,慢指針每次移動一個節點。
如果鏈表不存在環,那麼經過不斷的移動,快指針肯定會找到隊尾元素。
如下圖 :

這裏很好理解。
如果鏈表存在環,那麼經過不斷的移動,快慢指針最終會相遇,同時指向某個節點。
如下圖:

這是爲什麼呢?快指針再次跨過慢指針我們可以理解,爲什麼會恰好相遇在某個節點,而不是每次都恰好越過慢指針呢?

答案是並不會,原因是:(防盜連接:本文首發自http://www.cnblogs.com/jilodream/ )
快慢指針經過移動後,同時處在環中,假設快指針通過由於速度快,再次趕上慢指針的節點差距爲N。由於快指針每次比慢指針快一步,導致N每次逐漸縮小1,因此這個N=1。
感興趣的讀者可以自己在紙上畫一下。
下面我們直接來看代碼

 1     public boolean hasCycle(ListNode head) {
 2         if (head == null) {
 3             return false;
 4         }
 5         ListNode fast = head;
 6         ListNode low = head;
 7         while (true) {
 8             if (fast == null) {
 9                 return false;
10             }
11             if (fast.next == null) {
12                 return false;
13             }
14             if (fast.next.next == null) {
15                 return false;
16             }
17             fast = fast.next.next;
18             low = low.next;
19             if (fast == low) {
20                 return true;
21             }
22         }
23     }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章