1.滑动窗口
滑动窗口是一个很实用的算法(思想),关于字符串类型的许多题都可以用这个算法来解决。
今天找到一个用来解释滑动窗口算法的很直观的例子:转载链接
原文作者给出了一个很形象的类比:卷尺
滑动窗口中的这个“窗口”指的就是卷尺伸出来的部分,窗口的的头对应卷尺的头,窗口的尾就是卷尺伸出来部分的末尾,“滑动窗口”就是卷尺在一个给定字符串上移动和伸缩的过程。
2. 应用
1. 无重复字符的最长子串
问题描述:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。
问题分析:转载链接(有在原文基础上改动)
一个字符串,要在里面找出最长且没有重复字符的子串,就像拿着卷尺在上面不停地移动、伸缩测量。
子串就是这个卷尺的伸出部分,即一个窗口,左边缩进,右边拉出。
因为不能有重复的字符,在右端逐渐拉长的过程中,每新增加的一个新字符都要拿来和左侧子串中的所有字符做对比。
在下面的程序里,用 left 指向卷尺头部,用 right 指向卷尺尾部,k 则作为子串中字符的索引。
每次对比开始时,用 left 的值初始化 k(即从当前窗口左侧第一个字符开始对比),如发现重复字符,就将 k + 1的值赋给 left,即直接将窗口的左侧移动到现在窗口中重复字符的下一个字符位置。
窗口右侧每次向右滑动一格,如果窗口中子串包含窗口右侧下一个字符,左侧滑动一格或多格。
与枚举法相比,由于利用了子串中重复字符的位置,直接将窗口左侧跳到该字符的下一个位置,每次检查出重复减少了 k - left 个子串的自检。
代码实现(Python):
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
left = 0 #窗口左端
right = 0 #窗口右端
windowLengh = 0 #窗口长度
maxLength = 0 #最长无重复子串长度
length = len(s)
if(length == 0):
return 0
for right in range(0, length):
if(length-left < maxLength):
return maxLength #如果窗口左端到字符串末尾的总长度小于现在的最长无重复子串长度,那么就无需继续比较了
windowLengh +=1
if(right == length-1): ##达到最右端
break
for k in range(left, right+1): #从窗口左端开始比较
if(s[k] == s[right+1]): #如果重复
if(windowLengh > maxLength): #如果窗口长度大于目前最长无重复子串长度
maxLength = windowLengh #更新最长无重复字符串长度
left = k+1 #移动窗口左端
windowLengh = right - left + 1 #重新计算窗口长度
break
if(windowLengh > maxLength):
return windowLengh
else:
return maxLength