395. 每个字符至少重复 K 次的最长子串(Medium)/ 424. 最多替换 K 次后的最长重复子串(Medium)/ 1156.(最多交换1次)最长的单字符重复子串 /(非)重复串问题!!!

class Solution:
	# 递归
	def longestSubstring(self, s, k):
        if len(s) < k:
            return 0
            
        for c in set(s):
            if s.count(c) < k:
                return max(self.longestSubstring(t, k) for t in s.split(c))

        return len(s)
        
	# 前缀和+分治
    def longestSubstring(self, s: str, k: int) -> int:
        n = len(s)
        
        # 1. 计算前缀和
        prefix = [[0] * (n + 1) for _ in range(26)]
        for i in range(n):
            for j in range(26):
                prefix[j][i+1] = prefix[j][i]  # 把前一个抄过来先
            prefix[ord(s[i])-97][i+1] += 1  # 注意下标

        # 2. 用栈实现后序遍历(因为本题答案是全局,因此可以迭代实现)
        stack, res = [(0, n - 1)], 0
        while stack:  # 枚举区间不存在则结束
            start, end = stack.pop()
            for i in range(start, end + 1):
                if prefix[ord(s[i])-97][end+1] - prefix[ord(s[i])-97][start] < k:
                    stack.extend([(start, i - 1), (i + 1, end)])
                    break
            else:  # 如果没有 break 则证明 [start, end] 区间满足条件则更新
                res = max(res, end - start + 1)

        return res

424. 最多替换 K 次后的最长重复子串

在这里插入图片描述

class Solution:
    def characterReplacement(self, s: str, k: int) -> int:
        num = [0] * 26 # 记录每个字符出现的次数
        n = len(s)
        maxn = left = right = 0

        # 使用右指针right来遍历每个字符
        while right < n:
            # 滑窗右指针指向的字符数加一
            num[ord(s[right]) - ord("A")] += 1
            # 对于每个访问到的字母ch,更新:重复最多字母出现的次数maxn
            maxn = max(maxn, num[ord(s[right]) - ord("A")])

            # 判断若得到当前的最大长度的重复串是否满足条件(最多替换k次)
            if right - left + 1 - maxn > k:
                # 左指针前移一位(左、右指针只能前移或不动)
                # 左指针对应的字符数也需要减一
                num[ord(s[left]) - ord("A")] -= 1
                left += 1
            right += 1
        
        return right - left # 因为右指针加一了,所以这里不需要多减一

在这里插入图片描述

1156. (最多交换1次)最长的单字符重复子串

在这里插入图片描述

class Solution:
    def maxRepOpt1(self, text: str) -> int:
        cnt = Counter(text)
        n = len(text)
        ans = 0
        i = 0

        while i < n:
            # 先找第1段(第1段必有,因为长度至少为1)
            j = i
            while j < n and text[j] == text[i]:
                j += 1
            l = j - i # 第1段长度
            
            # 尝试寻找第2段
            k = j + 1
            while k < n and text[k] == text[i]:
                k += 1
            r = k - j - 1 # 第2段长度(可能为0)

            # 更新最大值(此时+1表示使用1次交换)
            ans = max(ans, min(l + r + 1, cnt[text[i]]))

            i = j

        return ans

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值