算法-滑动窗口思想

滑动窗口思想:从左至右滑动,不满足时,右边沿前进;窗口内子串满足时,左边沿前进缩小子串范围。
下面是一些你可以用来确定给定问题可能需要滑动窗口的方法:
问题的输入是一种线性数据结构,比如链表、数组或字符串
你被要求查找最长/最短的子字符串、子数组或所需的值
你可以使用滑动窗口模式处理的常见问题:
大小为 K 的子数组的最大和(简单)
带有 K 个不同字符的最长子字符串(中等)
寻找字符相同但排序不一样的字符串(困难)

一、所有的子数组中累加和为k的最长子数组长度:
给定一个无序数组arr,其中元素可正,可负,可0,给定一个整数k。
求arr 所有的子数组中累加和为k的最长子数组长度。
输入 [1,-2,1,1,1]
2
输出 5

# 要找的目标子串符合条件:s2-s1=k,用dict_s1记录{s1的和:s1的下标}
# s1的下标从-1到p ,s2的下标从0到q
class Solution:
    def FindMaxLenOfSubStr(self, arr: list[int], k: int) -> int:
        dict_s1 = {0: -1}
        Mlen, sum_s2 = 0, 0
        p, q = 0, 0
        for i, num in enumerate(arr):
            sum_s2 += num
            if sum_s2-k in dict_s1:
                if Mlen < i - dict_s1[sum_s2-k]:
                    Mlen = i - dict_s1[sum_s2-k]
                    p = dict_s1[sum_s2-k]
                    q = i
                    # 记录目标子串的起始前和结束下标
            if sum_s2 - k not in dict_s1:
                dict_s1[sum_s2 - k] = i
        print(arr[p+1: q+1])
        print(p, q)
        return Mlen


if __name__ == '__main__':
    x = Solution()
    print(x.FindMaxLenOfSubStr([1, -2, 1, 1, 1], 2))

相似例题:给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
一样的解法,将字符串换成数组而已:

class Solution:
    def maxLength(self , arr ):
        # write code here
        if not arr:
            return 0
        Mlen = 0
        win = []
        for i,n in enumerate(arr):
            if n in win:
                win = win[win.index(n)+1:]
            win.append(n)
            Mlen = max(Mlen, len(win))
        return Mlen

二、求数组中满足和>=s 的长度最小连续子数组
给定一个含有n个正整数数组和正整数s,找出该数组中满足和大于等于s的长度最小连续子数组。不存在返回0
示例: s=7,nums= [2,3,1,2,4,3]
输出2

class Solution:
    def MinlenOfSubstr(self, nums, s):
        Mlen, sum = len(nums), 0
        window = [] 
        flag = 0 #记录滑动过程中是否满足
        for i,n in enumerate(nums):
            sum += n
            #不满足时,窗口右沿扩展
            if sum < s:
               window.append(n)
           else:
               window.append(n)
               #满足时,窗口左沿缩小
               while sum >= s:
                   flag = 1
                   if Mlen > len(window):
                       Mlen = len(window)
                   sum -= window[0]
                   window.pop(0)
       if flag == 0:
           return 0
       else:
           return Mlen     

三、求字符串内无重复子串的最长长度 / 最长无重复子数组
思想:求两个相同字符相隔的最长长度
解法一:定义一个列表作为滑动窗口,不符合时扩展右沿;符合时将左沿缩至重复的下标+1。
目的:求出重复字符相隔的最大长度。

class Solution:
    def MLenOfSubStr(self, s: str) -> int:
        if not s:
            return 0
        list_win = []  #定义滑动窗口
        Mlen = 0
        for i, a in enumerate(s):
            if a not in list_win:
                list_win.append(a) #不重复的话右沿扩展
            else:
                #!!重复的时候,取重复字符下标+1位开始,重新计算。
                list_win = list_win[list_win.index(a)+1:]
                list_win.append(a) #重复也得后走
            Mlen = max(Mlen, len(list_win))
        return Mlen

if __name__ == "__main__":
    x = Solution()
    print(x.MLenOfSubStr("abccdbaab"))

四、求数组中和为目标值的两个数
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        if not nums:
            return []
        dst = [] #定义列表而不是字典,可以根据值找到索引
        for i, n in enumerate(nums):
            dst = nums[:i] #有序确保了索引能找到
            if target-n in dst:
                ix = dst.index(target-n)
                return [ix, i]
        return [ ]

五、求arr中所有子数组中累计和为k的最长子数组长度。
输入: [1, -2, 1, 1, 1]
输出: 5

class Solution:
	def FindMaxLenth(self, arr):
		Mlen, sum = 0, 0
		dict_s1 = {0: -1} # key为 s1的和,value为s1的结束位置。
		#假设和为k的目标串 为s2-s1 
		for i,n in enumerate(arr):
			sum += n #s2的和,k=s2-s1
			if sum-k in dict_s1:
				Mlen = max(Mlen, i-dict_s1[sum-k])
			else:
				dict_s1[sum-k] = i   #-1到i时
		return Mlen
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值