Leetcode 1234 替换子串得到平衡字符串

2025/04/12

1234. 替换子串得到平衡字符串

有一个只含有 'Q', 'W', 'E', 'R' 四种字符,且长度为 n 的字符串。

假如在该字符串中,这四个字符都恰好出现 n/4 次,那么它就是一个「平衡字符串」。

 

给你一个这样的字符串 s,请通过「替换一个子串」的方式,使原字符串 s 变成一个「平衡字符串」。

你可以用和「待替换子串」长度相同的 任何 其他字符串来完成替换。

请返回待替换子串的最小可能长度。

如果原字符串自身就是一个平衡字符串,则返回 0

 

示例 1:

输入: s = "QWER"
输出: 0
解释: s 已经是平衡的了。
''' 滑窗:
记d=len(s)//4  
如果在某个子串之外存在某个字符个数 >= d,因为替换后字符个数不会减少,则当前子串替换后不能满足 QWER字符个数都等于d
也就是说,只有某个子串之外的字符个数都 <=d,才会替换成功
借助滑动窗口,用r 从左到右枚举滑动的每个右边界。
初始化记录s中每个字符的个数 c
首先,从右侧进入一个字符s[r],窗口外s[r]字符减少一个,更新窗口外字符个数,也就是c[s[r]]-=1
然后,判断此时c中每种字符个数是否满足<=d
    如果满足,则使用当前滑窗l+1~r长度 r-l+1来更新答案,并且从左侧缩小窗口范围,把窗口左侧字符s[l]踢出窗口,判断是否仍然满足...一直到不满足条件。
    不满足,则尝试从右侧进入更多字符
'''
class Solutioin:
    def balancedString(self, s):
        # 记录滑窗之外的每个字符的出现个数
        c=Counter(s)
        d=len(s)//4
        if all(c[x]==d for x in 'QWER'): return 0
        l,r=0,0
        ans = len(s)
        while r<len(s):
            c[s[r]]-=1
            # l+1~r部分为将要替换的部分
            while all(c[x]<=d for x in 'QWER'):
                ans = min(ans,r-l+1)
                c[s[l]]+=1
                l+=1
            r+=1
        return ans
        
'''
二分+滑窗+计数
根据上面的分析,我们知道s中某个子串如果满足它之外的字符个数都<= d,则当前子串的长度就是满足条件的 一个答案
根据直觉我们还知道,如果s的长度越长,那么答案是会增加的,也就是满足条件的子串的长度会随着s的增加而增加
根据这个单调性,我们就可以从小到大对 子串长度进行二分。
如果一个长度len下存在 某个子串,s中在它之外的字符个数都<=d,则len符合条件
又因为,我们是从小到大枚举的,所以得到的答案就是最小的答案了。
'''
class Solution:
    def balancedString(sef, s: str) -> int:
        c=Counter(s)
        n=len(s)
        d=n//4
        # 当前字符已经满足条件
        if all(c[x]==d for x in 'QWER'): return 0
        def check(limit):
            inner = Counter(s[:limit])
            outer = c-inner
            # 窗口从0位置 向右移动寻找是否有满足条件的子串
            # 枚举窗口的左边界
            for i in range(n-limit+1):
                # 当前位置是否满足条件
                if all(outer[x]<=d for x in 'QWER'):
                    return 1
                # 左边界字符从窗口出去
                inner[s[i]]-=1
                outer[s[i]]+=1
                # 是否存在右边界字符
                if i+limit<n:
                    # 右边界字符进入窗口
                    inner[s[i+limit]]+=1
                    outer[s[i+limit]]-=1
            return 0
        # 枚举可能的子串长度 1~n-1
        l,r=1,n-1
        while l<r:
            m=l+r>>1
            if not check(m):
                l=m+1
            else: r=m
        return l

Post Directory