雙指標,指的是在遍歷物件的過程中,不是普通的使用單個指標進行訪問,而是使用兩個相同方向(快慢指標)或者相反方向(對撞指標)的指標進行掃瞄,從而達到相應的目的。
換言之,雙指標法充分使用了陣列有序這一特徵,從而在某些情況下能夠簡化一些運算。
在leetcode
題庫中,關於雙指標的問題還是挺多的。雙指標
截圖來之 leetcode 中文官網
對撞指標是指在陣列中,將指向最左側的索引定義為左指標(left)
,最右側的定義為右指標(right)
,然後從兩頭向中間進行陣列遍歷。
對撞陣列適用於連續陣列和字串,也就是說當你遇到題目給定連續陣列和字元床時,應該第一時間想到用對撞指標解題。偽**大致如下:
public編寫乙個函式,其作用是將輸入的字串反轉過來。輸入字串以字元陣列 char 的形式給出。void
find (int list)
}
不要給另外的陣列分配額外的空間,你必須原地修改輸入陣列、使用 o(1) 的額外空間解決這一問題。
你可以假設陣列中的所有字元都是 ascii 碼表中的可列印字元。
示例 1:
輸入:["h","e","l","l","o"]示例 2:輸出:["o","l","l","e","h"]
輸入:["h","a","n","n","a","h"]解答可以套用前面的偽**:輸出:["h","a","n","n","a","h"]
class給定乙個含有 n 個正整數的陣列和乙個正整數 s ,找出該陣列中滿足其和 ≥ s 的長度最小的 連續 子陣列,並返回其長度。如果不存在符合條件的子陣列,返回 0。solution
return
; }
}
示例:
輸入:s = 7, nums = [2,3,1,2,4,3]解答輸出:2解釋:子陣列 [4,3] 是該條件下的長度最小的子陣列。
class雖然這道題目也是用的雙指標,但是實際上採用滑動視窗的演算法思想,具體可以看文章:滑動視窗演算法基本原理與實踐。solution
right++;
}if (len == integer.max_value) return 0;
return
len;}}
快慢指標也是雙指標,但是兩個指標從同一側開始遍歷陣列,將這兩個指標分別定義為快指標(fast)
和慢指標(slow)
,兩個指標以不同的策略移動,直到兩個指標的值相等(或其他特殊條件)為止,如 fast 每次增長兩個,slow 每次增長乙個。
以leetcode 141.環形鍊錶為例,,判斷給定鍊錶中是否存在環,可以定義快慢兩個指標,快指標每次增長乙個,而慢指標每次增長兩個,最後兩個指標指向節點的值相等,則說明有環。就好像乙個環形跑道上有一快一慢兩個運動員賽跑,如果時間足夠長,跑地快的運動員一定會趕上慢的運動員。
快慢指標一般都初始化指向鍊錶的頭結點 head,前進時快指標 fast 在前,慢指標 slow 在後,巧妙解決一些鍊錶中的問題。
這應該屬於鍊錶最基本的操作了,如果讀者已經知道這個技巧,可以跳過。
單鏈表的特點是每個節點只知道下乙個節點,所以乙個指標的話無法判斷鍊錶中是否含有環的。
如果鍊錶中不包含環,那麼這個指標最終會遇到空指標 null 表示鍊錶到頭了,這還好說,可以判斷該鍊錶不含環。
boolean但是如果鍊錶中含有環,那麼這個指標就會陷入死迴圈,因為環形陣列中沒有 null 指標作為尾部節點。hascycle(listnode head)
經典解法就是用兩個指標,乙個每次前進兩步,乙個每次前進一步。如果不含有環,跑得快的那個指標最終會遇到 null,說明鍊錶不含環;如果含有環,快指標最終會和慢指標相遇,說明鍊錶含有環。
就好像乙個環形跑道上有一快一慢兩個運動員賽跑,如果時間足夠長,跑地快的運動員一定會趕上慢的運動員。
boolean這個問題其實不困難,有點類似腦筋急轉彎,先直接看**:hascycle(listnode head)
return
false
;}
listnode detectcycle(listnode head)可以看到,當快慢指標相遇時,讓其中任乙個指標重新指向頭節點,然後讓它倆以相同速度前進,再次相遇時所在的節點位置就是環開始的位置。slow =head;
while (slow !=fast)
return
slow;
}
類似上面的思路,我們還可以讓快指標一次前進兩步,慢指標一次前進一步,當快指標到達鍊錶盡頭時,慢指標就處於鍊錶的中間位置。
listnode slow, fast;當鍊表的長度是奇數時,slow 恰巧停在中點位置;如果長度是偶數,slow 最終的位置是中間偏右:slow = fast =head;
while (fast != null && fast.next != null
) //
slow 就在中間位置
return slow;
尋找鍊錶中點的乙個重要作用是對鍊錶進行歸併排序。
回想陣列的歸併排序:求中點索引遞迴地把陣列二分,最後合併兩個有序陣列。對於鍊錶,合併兩個有序鍊錶是很簡單的,難點就在於二分。
我們的思路還是使用快慢指標,讓快指標先走 k 步,然後快慢指標開始同速前進。這樣當快指標走到鍊錶末尾 null 時,慢指標所在的位置就是倒數第 k 個鍊錶節點(為了簡化,假設 k 不會超過鍊錶長度):
listnode slow, fast;這也許是雙指標技巧的最高境界了,如果掌握了此演算法,可以解決一大類子字串匹配的問題,不過「滑動視窗」演算法比上述的這些演算法稍微複雜些。slow = fast =head;
while (k-- > 0)
fast =fast.next;
while (fast != null
) return slow;
具體原理和實踐可以詳見文章:滑動視窗演算法基本原理與實踐
滑動視窗演算法基本原理與實踐
廣度優先搜尋原理與實踐
深度優先搜尋原理與實踐
雙指標演算法基本原理和實踐
分治演算法基本原理和實踐
動態規劃演算法原理與實踐
演算法筆記
雙指標演算法基本原理和實踐
雙指標,指的是在遍歷物件的過程中,不是普通的使用單個指標進行訪問,而是使用兩個相同方向 快慢指標 或者相反方向 對撞指標 的指標進行掃瞄,從而達到相應的目的。換言之,雙指標法充分使用了陣列有序這一特徵,從而在某些情況下能夠簡化一些運算。在leetcode題庫中,關於雙指標的問題還是挺多的。雙指標 截...
跳蚤演算法 基本原理。
跳蚤演算法 基本原理。一 演算法的誕生及設計初衷。傳統教材中取得x個0 to n之間不重複隨機數的方法一般是這樣 x個不重複隨機數輸出到a 陣列 for i 1 to x dor int rnd n 1 c 確定r不包含在a 內 loop until c 將r新增到a next 由於r可能與a 內的...
RSA演算法基本原理
圖為 rsa公開金鑰演算法的發明人,從左到右ron rivest,adi shamir,leonard adleman.攝於1978年 素數是這樣的整數,它除了能表示為它自己和1的乘積以外,不能表示為任何其它兩個整數的乘積。例如,15 3 5,所以15不是素數 又如,12 6 2 4 3,所以12也...