基於雙指標的滑動視窗方法在陣列問題中的應用
LeetCode中有道題:取一個字串中不含重複字元的最長子串的長度。原題是:Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters.
最直接的想法是暴力法窮舉所有的子串,取其中不包含重複字元的最長的一個。
result=0 for i=1 to n-1 for j=i+1 to n s=substring(i,j) if(s.allunique() and s.length>result) result=s.length return result
其中判斷一個字串是否包含不重複的字元,藉助集合的資料結構,至少需要一趟比較。所以,暴力窮舉的時間複雜度將達到
O()。當需要處理的字元創較長時,LeetCode平臺將拒絕接受。
考慮對暴力方法進行優化:當substring(i,j)含有重複字元時,那麼substring(i,k) k[i+1,n] 一定會包含重複字元,不用再進行判斷即可,此時需要將頭部指標i向後移動一個單位繼續判斷即可;若substring(i,j)不含有重複字元,則將尾部指標j向後移動一個單位繼續判斷。i和j之間則形成了一個滑動視窗。所以基於雙指標i和j形成如下優化演算法:
i=0 j=1 result=0 while(i<n and j<n) while(j<n and substring(i,j).contains(string.chatAt(j))) j++ result=result>j-i?result:j-i i++ return result
i,j整體移動一遍就能得到結果,演算法的時間複雜度是O(n),最壞的情況是2*n。
我們重新審視一下這個雙指標形成的滑動視窗,避免了重複的比較和判斷,是處理陣列和字串問題的有效優化方法。LeetCode中給出的解決策略中這樣定義滑動視窗:
A sliding window is an abstract concept commonly used in array/string problems. A window is a range of elements in the array/string which usually defined by the start and end indices, i.e. [i, j)[i,j) (left-closed, right-open). A sliding window is a window "slides" its two boundaries to the certain direction. For example, if we slide [i, j)[i,j) to the right by 11 element, then it becomes [i+1, j+1)[i+1,j+1) (left-closed, right-open).
再另一個經典問題快速排序中,我們同樣可以使用滑動視窗的思想來進行一趟partition。
partition(A,p,r)
x=A[r]
i=p-1
for j=p to r-1
if A[j]<=x
i++
exchange A[i] with A[j]
exchange A[i+1] with A[r]
retur i+1