【力扣-Python-滑动窗口经典题】567.字符串的排列 | 424.替换后的最长重复字符 | 76.最小覆盖子串

567. 字符串的排列

题意: 给定两个小写 字母字符串s1和s2,判断s2中是否存在一个连续 子串,是s1的某种排列(排列:字符顺序可不同,但出现次数必须完全相同)

**思路:**固定长度的滑动窗口+频次数组(对每个窗口做一次频次对比)

  • 窗口长度等于s1的长度
  • 用两个长度26的数组,record[26]数组统计s1中每个字符出现的次数,win[26]数组统计当前窗口内字符的出现次数
  • 数组下标0-25对应字母a-z
  • 只要某一时刻,win数组==record数组,就返回True
python 复制代码
class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:
        record = [0] * 26    # s1的字符频次
        for i in s1:
            pos = ord(i) - ord('a')
            record[pos] += 1

        left = 0
        win = [0] * 26   # 当前窗口的字符频次
        for right in range(len(s2)):    # 左右指针在s2上滑动窗口
            # 右指针每向右一步,就把新字符加入窗口计数
            pos = ord(s2[right]) - ord('a')
            win[pos] += 1
            # 当窗口长度>s1长度时,左指针右移,把移出窗口的字符计数-1
            if right - left + 1 > len(s1):
                win[ord(s2[left]) - ord('a')] -= 1
                left += 1
            # 比较两个频次数组
            if record == win:
                return True
        return False
  • 时间复杂度:O(n),n为s2的长度
    • 虽然每次都要比较两个长度为26的数组,但因为26是常数,所以总体还是O(n)
  • 空间复杂度:O(1)
    • 只用了两个固定大小的频次数组

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

**题意:**给定只包含大写字母的字符串s和整数k,最多可以替换k个字符为任意大写字母,求替换后能得到的最长相同字符子串长度

**思路:**滑动窗口+哈希表

  • 用一个滑动窗口在字符串上从左到右移动
  • 用一个哈希表统计窗口中每个字符出现的次数
  • 同时维护一个变量maxCount ,表示当前窗口中出现次数最多的那个字符的数量
  • 窗口的长度 - maxCount ,就是把当前窗口变成全相同字符所需要替换的字符数
    • 如果这个值小于等于k,说明窗口是合法的,可以继续扩展
    • 否则说明替换次数不够,需要收缩左边界

**重要优化点:**收缩窗口时,不重新计算maxCount,而是保留历史最大值,即使它偏大,也不会影响最终答案,只是让窗口判断更宽松,从而避免重复计算

python 复制代码
class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        left = 0
        win = [0] * 26     # 统计窗口内字符出现的次数
        maxCount = 0    # 窗口内出现过的最大字符频次
        res = 0
        for right in range(len(s)):
            # 每加入一个字符就更新字符计数
            pos = ord(s[right]) - ord('A')
            win[pos] += 1
            maxCount = max(win)

            win_len = right - left + 1
            # 窗口不合法,需要替换的字符数>k,收缩左边界            
            if win_len - maxCount > k:
                win[ord(s[left]) - ord('A')] -= 1
                left += 1                
            res = max(res, right-left+1)

        return res
  • 时间复杂度:O(n),n为字符串的长度
    • 每个字符只会被左右指针各访问一次
  • 空间复杂度:O(1)
    • 哈希表中最多存26个大写字母

76. 最小覆盖子串

**题意:**两个字符串,一个s,一个t,要求返回s中涵盖t所有字符的最小子串

思路:

  • t_dic字典统计t里的字符及出现次数

  • 生成一个字典win_dic,该字典的key和t_dic的key是一样的,value通过后续遍历s字符串的时候再统计

  • 定义一个函数isContain,该函数的目的是看win_dic里每个key的值是不是 ≥ t_dic里每个key的值,若不是就直接返回False

  • 最后就是滑动窗口的老步骤,right指针在s字符串中逐步往右遍历,若遍历到的字符在字典t_dic里(即是t字符串里的字符),则对应value加1;直到win_dic里每个key的值都 ≥ t_dic里每个key的值;再移动左指针left

python 复制代码
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        if len(t) > len(s):
            return ""

        # key是t中的字符,value是出现次数
        t_dic = {}
        for i in t:
            if i not in t_dic:
                t_dic[i] = 1
            else:
                t_dic[i] += 1

        # 窗口dic
        win_dic = {}
        for k in t_dic:
            if k not in win_dic:
                win_dic[k] = 0

        def isContain(cur_dic, final_dic):
            for k in final_dic:
                if cur_dic[k] < final_dic[k]:
                    return False
            return True
        
        # 开始遍历s
        left, right = 0, 0
        win_size = float("inf")
        res = ""
        for right in range(len(s)):
            if s[right] in win_dic:
                win_dic[s[right]] += 1
            while isContain(win_dic, t_dic):
                if right-left+1 < win_size:
                    win_size = right-left+1
                    res = s[left: right+1]
                if s[left] in win_dic:
                    win_dic[s[left]] -= 1
                left += 1
        return res
相关推荐
玄冥剑尊3 小时前
贪心算法进阶
算法·贪心算法
玄冥剑尊3 小时前
贪心算法深化 I
算法·贪心算法
52Hz1183 小时前
力扣73.矩阵置零、54.螺旋矩阵、48.旋转图像
python·算法·leetcode·矩阵
BHXDML3 小时前
第一章:线性回归& 逻辑回归
算法·逻辑回归·线性回归
iAkuya3 小时前
(leetcode)力扣100 二叉搜索树种第K小的元素(中序遍历||记录子树的节点数)
算法·leetcode·职场和发展
Remember_9934 小时前
【LeetCode精选算法】滑动窗口专题二
java·开发语言·数据结构·算法·leetcode
Gorgous—l5 小时前
数据结构算法学习:LeetCode热题100-动态规划篇(下)(单词拆分、最长递增子序列、乘积最大子数组、分割等和子集、最长有效括号)
数据结构·学习·算法
北京地铁1号线6 小时前
2.3 相似度算法详解:Cosine Similarity 与 Euclidean Distance
算法·余弦相似度
圣保罗的大教堂6 小时前
leetcode 1895. 最大的幻方 中等
leetcode