逐步增加遞增子串行 二分查詢的妙用 判定子串行

2021-10-12 18:17:00 字數 3040 閱讀 3073

labuladong

二分查詢本身不難理解,難在巧妙地運用二分查詢技巧。對於乙個問題,你可能都很難想到它跟二分查詢有關,比如前文 最長遞增子串行就借助乙個紙牌遊戲衍生出二分查詢解法。

今天再講一道巧用二分查詢的演算法問題:如何判定字串s是否是字串t的子串行(可以假定s長度比較小,且t的長度非常大)。舉兩個例子:

s = "abc", t = "ahbgdc", return true.

s = "axc", t = "ahbgdc", return false.

題目很容易理解,而且看起來很簡單,但很難想到這個問題跟二分查詢有關吧?

首先,乙個很簡單的解法是這樣的:

bool issubsequence(string s, string t) 

return i == s.size();

}

其思路也非常簡單,利用雙指標i, j分別指向s, t,一邊前進一邊匹配子串行:

讀者也許會問,這不就是最優解法了嗎,時間複雜度只需 o(n),n 為t的長度。

是的,如果僅僅是這個問題,這個解法就夠好了,不過這個問題還有 follow up

如果給你一系列字串s1,s2,...和字串t,你需要判定每個串s是否是t的子串行(可以假定s相對較短,t很長)。

boolean issubsequence(string sn, string t);

你也許會問,這不是很簡單嗎,還是剛才的邏輯,加個 for 迴圈不就行了?

可以,但是此解法處理每個s時間複雜度仍然是 o(n),而如果巧妙運用二分查詢,可以將時間複雜度降低,大約是 o(mlogn),m 為 s的長度。由於 n 相對 m 大很多,所以後者效率會更高。

二分思路主要是對t進行預處理,用乙個字典index將每個字元出現的索引位置按順序儲存下來(對於 ascii 字元,可以用大小為 256 的陣列充當字典):

比如對於這個情況,匹配了 "ab",應該匹配 "c" 了:

按照之前的解法,我們需要j線性前進掃瞄字元 "c"。但現在借助index中記錄的資訊,可以二分搜尋index[c]中比 j 大的那個索引,在上圖的例子中,就是在[0,2,6]中搜尋比 4 大的那個索引:

這樣就可以快速得到下乙個 "c" 的索引 6。現在的問題就是,如何用二分查詢計算那個恰好比 4 大的索引呢?答案是,尋找左側邊界的二分搜尋就可以做到。

在前文 二分查詢演算法詳解中,詳解了如何正確寫出三種二分查詢演算法的細節。二分查詢返回目標值val的索引,對於搜尋左側邊界的二分查詢,有乙個特殊性質:

val不存在時,得到的索引恰好是比val大的最小元素索引

什麼意思呢,就是說如果在陣列[0,1,3,4]中搜尋元素 2,演算法會返回索引 2,也就是元素 3 的位置,元素 3 就是陣列中大於 2 的最小元素。所以我們可以利用二分搜尋避免線性掃瞄。

以上就是搜尋左側邊界的二分查詢,等會兒會用到,其中的細節可以參見 二分查詢演算法詳解,這裡不再贅述。

這裡以處理單個字串s為例,對於多個字串s,把預處理部分單獨抽出來即可。

演算法執行的過程是這樣的:

可見借助二分查詢,演算法的效率是可以大幅提公升的:預處理時需要 o(n) 時間,每次匹配子串行的時間是 o(mlogn),比之前每次匹配都要 o(n) 的時間要高效得多。

當然,如果只需要判斷乙個 s 是否是 t 的子串行,是不需要二分查詢的,一開始的 o(n) 解法就是最好的,因為雖然二分查詢解法處理每個 s 只需要 o(mlogn),但是還需要 o(n) 時間構造 index 字典預處理,所以處理單個s時沒有必要。

以上就是二分查詢技巧判定子串行的全部內容,希望你能有所收穫。

●編號1041,輸入編號直達本文

●輸入m獲取文章目錄

程式設計師數學之美

程式設計師數學學習

鍛鍊數學邏輯思維

最長遞增子串行!!!(DP ,二分)

最長遞增子串行 time limit 1000 ms memory limit 32768 k total submit 158 64 users total accepted 68 56 users rating special judge no description 給出乙個數字序列求其最長的...

二分優化 單調遞增子串行(二)NYOJ(214)

例題 題解 該題很資料量很大用傳統的動態規劃演算法寫,會tle,所以需要用二分優化演算法,我們可以定義乙個棧stack,可以說是單調棧,利用二分查詢,保持棧的單調行,從一層for迴圈裡找到每乙個ans所在的位置 以樣例1為例 1910 511213 stack 1 a 0 先把第乙個值入棧 123 ...

Python 查詢序列的最長遞增子串行

什麼是序列的最長遞增子串行?答 在乙個數值串行中,找到乙個子串行,使得這個子串行元素的數值依次遞增,並且這個子串行的長度盡可能地大。這就是所謂的最長遞增子串行 from itertools import combinations from random import sample defsubasc...