雙指標演算法基本原理和實踐

2021-10-22 04:38:15 字數 3044 閱讀 4738

雙指標,指的是在遍歷物件的過程中,不是普通的使用單個指標進行訪問,而是使用兩個相同方向(快慢指標)或者相反方向(對撞指標)的指標進行掃瞄,從而達到相應的目的。換言之,雙指標法充分使用了陣列有序這一特徵,從而在某些情況下能夠簡化一些運算。在leetcode題庫中,關於雙指標的問題還是挺多的。雙指標

截圖來之 leetcode 中文官網

對撞指標是指在陣列中,將指向最左側的索引定義為左指標(left),最右側的定義為右指標(right),然後從兩頭向中間進行陣列遍歷。

對撞陣列適用於連續陣列和字串,也就是說當你遇到題目給定連續陣列和字元床時,應該第一時間想到用對撞指標解題。
偽**大致如下:

public void find (int list) 

}

編寫乙個函式,其作用是將輸入的字串反轉過來。輸入字串以字元陣列 char 的形式給出。不要給另外的陣列分配額外的空間,你必須原地修改輸入陣列、使用 o(1) 的額外空間解決這一問題。你可以假設陣列中的所有字元都是 ascii 碼表中的可列印字元。

示例 1:

輸入:["h","e","l","l","o"]

輸出:["o","l","l","e","h"]

示例 2:

輸入:["h","a","n","n","a","h"]

輸出:["h","a","n","n","a","h"]

解答:可以套用前面的偽**

class solution 

right++;

}if (len == integer.max_value) return 0;

return len;}}

雖然這道題目也是用的雙指標,但是實際上採用滑動視窗的演算法思想,具體可以看文章:滑動視窗演算法基本原理與實踐。 

快慢指標也是雙指標,但是兩個指標從同一側開始遍歷陣列,將這兩個指標分別定義為快指標(fast)慢指標(slow),兩個指標以不同的策略移動,直到兩個指標的值相等(或其他特殊條件)為止,如 fast 每次增長兩個,slow 每次增長乙個。以leetcode 141.環形鍊錶為例,,判斷給定鍊錶中是否存在環,可以定義快慢兩個指標,快指標每次增長乙個,而慢指標每次增長兩個,最後兩個指標指向節點的值相等,則說明有環。就好像乙個環形跑道上有一快一慢兩個運動員賽跑,如果時間足夠長,跑地快的運動員一定會趕上慢的運動員。 

快慢指標一般都初始化指向鍊錶的頭結點 head,前進時快指標 fast 在前,慢指標 slow 在後,巧妙解決一些鍊錶中的問題。

這應該屬於鍊錶最基本的操作了,如果讀者已經知道這個技巧,可以跳過。

單鏈表的特點是每個節點只知道下乙個節點,所以乙個指標的話無法判斷鍊錶中是否含有環的。

如果鍊錶中不包含環,那麼這個指標最終會遇到空指標 null 表示鍊錶到頭了,這還好說,可以判斷該鍊錶不含環。

boolean hascycle(listnode head)
但是如果鍊錶中含有環,那麼這個指標就會陷入死迴圈,因為環形陣列中沒有 null 指標作為尾部節點。經典解法就是用兩個指標,乙個每次前進兩步,乙個每次前進一步。如果不含有環,跑得快的那個指標最終會遇到 null,說明鍊錶不含環;如果含有環,快指標最終會和慢指標相遇,說明鍊錶含有環。就好像乙個環形跑道上有一快一慢兩個運動員賽跑,如果時間足夠長,跑地快的運動員一定會趕上慢的運動員。 

這個問題其實不困難,有點類似腦筋急轉彎,先直接看**:

listnode detectcycle(listnode head) 

slow = head;

while (slow != fast)

return slow;

}

可以看到,當快慢指標相遇時,讓其中任乙個指標重新指向頭節點,然後讓它倆以相同速度前進,再次相遇時所在的節點位置就是環開始的位置。

類似上面的思路,我們還可以讓快指標一次前進兩步,慢指標一次前進一步,當快指標到達鍊錶盡頭時,慢指標就處於鍊錶的中間位置。

listnode slow, fast;

slow = fast = head;

while (fast != null && fast.next != null)

// slow 就在中間位置

return slow;

當鍊表的長度是奇數時,slow 恰巧停在中點位置;如果長度是偶數,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也...