基于双指针的滑动窗口方法在数组问题中的应用

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(n^{3})。当需要处理的字符创较长时,LeetCode平台将拒绝接受。

考虑对暴力方法进行优化:当substring(i,j)含有重复字符时,那么substring(i,k) k\in[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

猜你喜欢

转载自blog.csdn.net/xucr1111/article/details/83962738