满足...的最长/短子数组的长度
题目
给定一个字符串,求满足…的最长/短子数组的长度。其中...
部分可以是不含重复字符
或含重复字符
等。
解题思路
对于这种求满足一定条件的最长/短子数组长度的题目,可以使用滑动窗口法进行处理。
1.求解:满足不含重复字符的最长子串的长度
给定一个字符串,求满足不含重复字符的最长/短子数组的长度(同时使用set判别是否重复):
- 特判:若字符串的长度小于2,返回字符串
- 初始化:
vis = set()
:记录重复字符maxlen = 0
:满足不含重复字符的最长子串的长度curlen=0
:滑动窗口当前的不含重复子串的窗口长度left=0
:窗口的左端指针
- 处理右端值:遍历字符串作为右端点值
rightvalue
- 当前窗口长度
curlen
加1 - 处理左端值:若
rightvalue
出现在vis
中,说明左端值出现重复:- 将左端值从
vis
中删除 - 左端指针
left
加1 - 当前窗口长度
curlen
减1
- 将左端值从
- 由当前窗口长度
curlen
来更新最大长度maxlen
- 将右端值
x
添加到vis
中
- 当前窗口长度
- 返回最大长度
maxlen
code1.1:满足不含重复字符的最长子串的长度
def lengthOfLongestSubstring(s:str)->int:
size = len(s)
if size<2: return size
vis = set()
left = 0
curlen = maxlen = 0
for rightvalue in s:
curlen += 1
while rightvalue in vis:
vis.remove(s[left])
left += 1
curlen -= 1
maxlen = max(maxlen, curlen)
vis.add(rightvalue)
return maxlen
对1的扩展:
- 如果求最短长度,只需要把
maxlen
的初始化改为Inf
,再在更新长度时使用min
即可。 - 若要求具有最长重复字符的最短子串,如
12333455678
,则要求的子串为333
。我们可以更改下滑窗左指针的滑动规则:当左指针与右指针指向元素不同时,左指针=右指针。
code1.2 具有最长重复字符的最短子串
def repeatSubStr(s:str)->int:
if len(s)<2: return len(s)
curlen = maxlen = 0
left = 0
for right,rightvalue in enumerate(s):
if s[left] != rightvalue:
left = right
curlen = right - left + 1
maxlen = max(maxlen, curlen)
return maxlen
2.求解:最长重复子数组(公共子数组)
给定两个整数数组A
和B
,返回这两个数组中公共的、长度最长的子数组的长度。
如:
输入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
输出:3
解释:
长度最长的公共子数组是 [3, 2, 1] 。
这也是满足一定条件的最长子数组的问题。这里的条件变为了两个数组公共部分
。
我们将A、B两个数组的比较长的数组作为固定数组Sta,将较短的数组作为滑窗数组Mov。并且我们在Sta
数组的首尾添加Mov
数组长度的None
,即我们得到Sta
和Mov
为:
addPartA = [None for _ in range(size_A)]
addPartB = [None for _ in range(size_B)]
Sta = addPartB[:]+A+addPartB[:] if size_A>= size_B \
else addPartA[:]+B+addPartA[:]
Mov = B if size_A>=size_B else A
我们对Sta
进行固定滑窗处理,要进行len(A)+len(B)
次的滑窗比较。
在滑窗比较时,如果对应索引的值相等,则公共部分的长度cnt
加1,若不等,则cnt=0
.
总体流程为:
- Sta为A/B中较长的数组在首尾添加较短数组长度的None,表示不移动的数组;Mov为A/B中较短的数组表示滑窗
- 对Sta进行滑窗处理,计算滑窗过程中最长公共子串的长度
- 得到Sta与Mov要比较的部分
- 对Sta与Mov要比较的部分进行计算最长的子串长度
- 更新最长子串的长度
其中,对Sta与Mov要比较的部分进行计算最长的子串长度为:
for j in range(size_M):
if tmp[j] == Mov[j]:
cnt += 1
resTmp = max(resTmp, cnt)
else:
cnt = 0
code2:最长重复子数组(公共子数组)
class Solution:
def findLength(self, A: List[int], B: List[int]) -> int:
size_A,size_B = len(A),len(B)
addPartA = [None for _ in range(size_A)]
addPartB = [None for _ in range(size_B)]
#get the `Sta` and `Mov`
Sta = addPartB[:] + A + addPartB[:] if size_A>size_B else addPartA[:] + B + addPartA[:]
Mov = B if size_A>size_B else A
size_mov = len(Mov)
maxlen = 0
#Compare the part of `Sta` with `Mov`
for left in range(size_A+size_B):
curlen = 0
Tmp = Sta[left:left+size_mov]
for idx in range(size_mov):
if Tmp[idx] == Mov[idx]:
curlen += 1
maxlen = max(maxlen,curlen)
else:#clear it if not equality
curlen = 0
return maxlen