满足...的最长/短子数组的长度(滑动窗口法)

题目

给定一个字符串,求满足…的最长/短子数组的长度。其中...部分可以是不含重复字符含重复字符等。

解题思路

对于这种求满足一定条件的最长/短子数组长度的题目,可以使用滑动窗口法进行处理。

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的扩展:
  1. 如果求最短长度,只需要把maxlen的初始化改为Inf,再在更新长度时使用min即可。
  2. 若要求具有最长重复字符的最短子串,如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.求解:最长重复子数组(公共子数组)

给定两个整数数组AB,返回这两个数组中公共的、长度最长的子数组的长度。
如:

输入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
输出:3
解释:
长度最长的公共子数组是 [3, 2, 1] 。

这也是满足一定条件的最长子数组的问题。这里的条件变为了两个数组公共部分
我们将A、B两个数组的比较长的数组作为固定数组Sta,将较短的数组作为滑窗数组Mov。并且我们Sta数组的首尾添加Mov数组长度的None,即我们得到StaMov为:

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 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值