【leetcode 3、424、209】【滑动窗口专题】

leetcode 3 无重复字符的最长子串


题目链接

https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/


解题思路与代码思路:

滑动窗口

要满足的条件有三:

  1. 不含有重复字符
  2. 最长的子串
  3. 返回长度

思路是遍历字符串,扩大窗口右端,同时把字母存进字典,直到遇见重复元素就缩小窗口左端;每次扩大右端都要查看之前的子串大小与当前窗口的大小比较,取最大值;当遍历完整个字符串,则任务完成。

利用集合解决

依次递增枚举子串起始位置,那么子串的结束位置也是递增的。假设k为起始位置,rk为结束位置,那么从k+1到rk的字符肯定不重复的,所以可以开始增大rk,直到遇到重复字符。
使用哈希集合来判断重复字符,左指针移动时就从集合移除一个字符,右指针移动时就添加字符进入集合


代码:

滑动窗口(这种写法比较直观好理解)
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        window = {}        #用于判断重复元素
        left,right = 0,0
        res = 0
        while right < len(s):  #右指针代表遍历完整个字符串
            c = s[right]  #取右指针元素
            right += 1    #扩大窗口
            window[c] = window.get(c,0) + 1
            
            #判断是否要缩小窗口
            while window[c] > 1 :
                d = s[left]
                left += 1
                window[d] -= 1
        
            res = max(res,right - left)
        return res
利用集合解决(这种写法仅仅看看)
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 哈希集合,记录每个字符是否出现过
        occ = set()
        n = len(s)
        # 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        rk, ans = 0, 0
        for i in range(n):
            if i != 0:
                # 左指针向右移动一格,移除一个字符
                occ.remove(s[i - 1])
            while rk  < n and s[rk] not in occ:
                # 不断地移动右指针
                occ.add(s[rk])
                rk += 1
            # 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i)
        return ans


复 杂 度 分 析 : \color{red}{复杂度分析:}
  1. 滑动窗口
  • 时间复杂度:O(N),其中 N 是字符串的长度。左指针和右指针分别会遍历整个字符串一次。
  • 空间复杂度:OO(∣Σ∣),其中 Σ 表示字符集(即字符串中可以出现的字符)

leetcode 424 替换后的最长重复字符


题目链接

https://leetcode-cn.com/problems/longest-repeating-character-replacement/

解题思路与代码思路:

滑动窗口

字符串限制在大写英文字母,要找到包含重复字母的最长子串,有一个灵活的点:至少可以替换任意位置字符K次。
延用上面的框架,那就是在扩大窗口的同时,添加K次的替换操作,做到当前最大重复;不满足【窗口大小-最多重复元素<=k】,那么左指针移动;


代码:

伪代码
# 替换后长度最长的字符串
# 能够 替换 k 个·
# 找出当前窗口最长的那个
# 把其他的替换掉
# 最多可替换k,那就替换k次
# AABABBA
# k = 1
# A   不需要替换
# AA, 不需要替换
# AAB, max_fre_num 是 A,有一个不是 A, 1 <= K, replace B -> AAA
# AABA, max_fre_num 是 A, 有一个不是 A, 1 <= k, replace B -> AAAA
# AABAB, 剩下的空位k没办法解决了, shrink window
# ABAB,shrink
# BAB, max_fre_num 是B, BBB
# BABB, BBBB
# BABBA, 剩下的空位k没办法解决了, shrink window
# window_length - max_fre_length  <= k , maxlength = window_length
# else shrink
实现代码
        res = 0
        dic = {}
        left = 0
        for right,val in enumerate(s):
            dic[val] = dic.get(val,0) + 1                    # 当前重复最多的字母个数
            while right - left + 1 - max(dic.values()) > k:  # 窗口翻转k个字符后是否还有别的字符
                dic[s[left]] -= 1
                left += 1

            res = max(res,right-left+1)
        return res


复 杂 度 分 析 : \color{red}{复杂度分析:}
  1. 滑动窗口
  • 时间复杂度:O(n)
  • 空间复杂度:O(1),26个大写英文字母

leetcode 209 长度最小子数组


题目链接

https://leetcode-cn.com/problems/minimum-size-subarray-sum/


解题思路与代码思路:

滑动窗口

要满足的条件是:

  1. 总和大于等于s
  2. 长度最小的连续子数组
  3. 返回长度

利用前后指针一起移动的方式;从第一个元素出发,右指针一直移动,直到总和大于等于s时,记录当前子数组长度,减掉子数组第一个值,移动左指针,继续循环。

写循环时要注意先后顺序,然后记录结果的result变量是个关键点,可以通过它来判断最后的结果判断, l e n ( n u m s ) + 1 len(nums)+1 len(nums)+1是因为不可能存在result大于nums长度,不写 l e n ( n u m s ) len(nums) len(nums)的原因主要是避免刚好result就是整个数组的和


代码:

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        if nums is None or len(nums) == 0:
            return 0

        result = len(nums)+1
        total = 0
        i,j = 0,0
        while j < len(nums):
            total += nums[j]
            j+=1
            while total >= s:
                result = min(result,j-i)
                total -= nums[i]
                i+=1
        return 0 if result == len(nums)+1 else result





复 杂 度 分 析 : \color{red}{复杂度分析:}
  1. 滑动窗口
  • 时间复杂度:O(n),其中 n是数组的长度。指针最多各移动 n次
  • 空间复杂度:O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值