滑动窗口刷题篇:剑指 Offer 59 - I. 滑动窗口的最大值 、无重复字符的最长字串、最小覆盖字串( Python实现)

本文介绍了两种高效的算法:一是使用滑动窗口优化求解最大值问题,通过保存窗口最大值减少计算量,降低时间复杂度;二是利用哈希集合解决无重复字符的最长子串问题,动态维护窗口并更新最长子串。这两个问题都展示了在处理数组和字符串时,如何通过巧妙的数据结构和算法设计提高效率。
摘要由CSDN通过智能技术生成

一、滑动窗口的最大值
在这里插入图片描述
方法一:暴力解法(两种代码实现)
今天做题发现这道n久之前做的题,现在似乎还是只能想到暴力解法,然而写了两种形式,果真是没什么进步
解法一:

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        #暴力解法
        if nums == [] or k == 0:
            return nums
        n = len(nums)
        window = nums[:k]
        res = []
        res.append(max(window))
        for i in range(k,n):
        	window.append(nums[j])
        	window.pop(0)
        	res.append(max(window)
        return res

解法二:

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        lens = len(nums)
        if nums == [] or k==0:
            return nums
        results = []
        for i in range(0,lens-k+1):
            windows = nums[i:i+k]
            max_num = max(windows)
            results.append(max_num)
        return results

这种方法的时间复杂度是o(nk)
这种每滑动一次就求一次当前窗口的最大值方法,非常低效因为每次滑动只有两个元素发生了变动(出去一个进来一个),而为了这两个元素的变动就要重新遍历一次求最大值的开销非常昂贵的。

方法二:保存窗口最大值减少计算量
解题思路:
可以考虑将当前窗口的最大值maxVal保存下来,滑动时用新增的元素num与maxVal进行bijiao :
maxVal >= num 输出 maxVal ,且maxVal不变
maxVal < num 输出 num, 更新 maxVal = num
当然,需要考虑一种特殊情况:保存下来的maxVal刚好等于上一个窗口的最左侧边界值,需要重新求当前窗口的最大值。
示例:
输入数组nums = [1,3,-1,-3,5,3,6,5,-1,2], k = 4

初始窗口元素:[1,3,-1,-3] maxVal = 3
第一次滑动后:[3,-1,-3,5] maxVal = 5
第二次滑动后:[-1,-3,5,3] maxVal = 5(最大值不变,减少计算量)
第三次滑动后:[-3,5,3,6] maxVal = 6
第四次滑动后:[5,3,6,5] maxVal = 6(最大值不变,减少计算量)
第五次滑动后:[3,6,5,-1] maxVal = 6(最大值不变,减少计算量)
第五次滑动后:[6,5,-1,2] maxVal = 6(最大值不变,减少计算量
可以看到,针对上面的示例,总共7个窗口,只有3个窗口进行求最大值的操作,从而大大减少时间复杂度(计算量)

复杂度分析
时间复杂度:
最坏时间复杂度:O(n) * k

空间复杂度:
只需要常数空间来存储最大值,所以时间复杂度是:O(1)

链接:https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/solution/chao-99bao-cun-chuang-kou-zui-da-zhi-jia-1gsn/

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if len(nums) == 0 or k == 1: # 异常值判断
            return nums 
        def get_max(arr): # 自定义获取某个数组最大值的函数
            result = arr[0]
            for a in arr:
                if a > result:
                    result = a  
            return result
        max_num = get_max(nums[:k]) # 获取初始最大值
        result = [max_num] # 填入初始最大值
        sid = 1 # 初始窗口左边界索引值
        fid = k # 初始窗口右边界索引值
        while fid < len(nums): # 只要右边界未超出输入数组长度都进行窗口滑动
            if max_num == nums[sid - 1]: # 核心判断逻辑:如果当前最大值等于上一个窗口左边界值
                max_num = get_max(nums[sid:fid]) # 重新判断计算当前窗口最大值
            if nums[fid] >= max_num: # 当前窗口新增的右边界值大于当前窗口最大值
                result.append(nums[fid]) # 将当前窗口的最大值追加到最终结果集
                max_num = nums[fid] # 重置当前窗口最大值
            else: # 否则直接追加当前窗口的最大值
                result.append(max_num)
            sid += 1 # 窗口滑动
            fid += 1 # 窗口滑动
        return result

二、无重复字符的最长字串
在这里插入图片描述

class Solution:
	def lengthOfLongestSubstring(self,s:str):
		# 哈希集合:记录每个字符是否出现过
		occ = set()
		rindex ,ans = -1,0 # 初始右指针索引为-1,相当于我们在字符串的左边界左侧,还没有开始移动
		n = len(s)
		for i in range(n):
			if i!=0:
				# 左指针向右移动一格,移除一个字符
				occ.remove(s[i-1])
			while rindex+1<n and s[rindex+1] not in occ:
				# 不断移动右指针
				occ.add(s[rindex+1])
				rindex+=1
			# 第i到第rindex字符是一个长无重复字符子串
			ans = max(ans, rindex-i+1)
		return ans

三、最小覆盖字串
在这里插入图片描述

class Solution:
	def minWindow(self, s:str, t:str) :
		need = collections.defaultdict(int)
		for c in t:
			need[c] +=1
		needCnt = len(t)
		i = 0
		res = (0, float('inf')) 
		# python中的正无穷:float('inf'),负无穷:float('-inf')
		for j,c in enumerate(s):
			if need[c]>0:
				needCnt-=1
			need[c] -=1
			if needCnt == 0:# 步骤一:滑动窗口包含了所有T元素
				while True:# 步骤二:增加i,排除多余元素
					c = s[i]
					if need[c]==0:
						break
					need[c]+=1
					i+=1
				if j-i< res[1]-res[0]:
					res = (i,j)
				need[s[i]] +=1 # 步骤三:i增加一个位置,寻找新的满足条件滑动窗口
				needCnt+=1
				i+=1
		# 如果res始终没被更新过,代表无满足条件的结果
		return '' if res[1]>len(s) else s[res[0]: res[1]+1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值