每日一题——替换子串得到平衡字符串

82 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 13 天,点击查看活动详情


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

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

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

 

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

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

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

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

 

示例 1:

输入: s = "QWER"
输出: 0
解释: s 已经是平衡的了。

示例 2:

输入: s = "QQWE"
输出: 1
解释: 我们需要把一个 'Q' 替换成 'R',这样得到的 "RQWE" (或 "QRWE") 是平衡的。

 

提示:

  • 1 <= s.length <= 10^5
  • s.length 是 4 的倍数
  • s 中只含有 'Q''W''E''R' 四种字符

思路

我们首先要做到的是找到那些超过 n / 4 次的字符,新的子字符串会代替原字符串,我们要求的是子字符串的长度,故对于未超过 n / 4 的字符不需要考虑。

对于子字符串来说,我们肯定是需要遍历得到的,对于所求子字符串的长度,我们只需要找到除了那些字符串后,我们的其余字符次数是不超过 n / 4 的。对于这类问题,我们可以通过滑动窗口的方式解决。

右边界负责将字符次数减一,表示移除该字符,左边界负责将字符次数加一,表示还原该字符,当当前剩余字符的次数符合要求时,我们才可以进行左边界的右移,同时,我们也可以将子字符串的长度记录下来,以比较获得最短子字符串的长度。

题解

class Solution {
    public int balancedString(String s) {
        int n = s.length();
        Map<Character, Integer> map = new HashMap<>();
        for(int i = 0; i < n; i++) {
            map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
        }
        if(check(map, n / 4)) {
            return 0;
        }
        int ans = Integer.MAX_VALUE;
        for(int i = 0, j = 0; j < n; j++) {
            map.put(s.charAt(j), map.get(s.charAt(j)) - 1);
            while(i <= j && check(map, n / 4)) {
                ans = Math.min(ans, j - i + 1);
                map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
                i++;
            }
        }
        return ans;
    }

    private boolean check(Map<Character, Integer> map, int size) {
        for(Map.Entry<Character, Integer> entry: map.entrySet()) {
            if(entry.getValue() > size) {
                return false;
            }
        }
        return true;
    }
}

如果你有其他的思路或者更好的解法,亦或者你发现了文章出现了错误或有不足,欢迎在评论区和我交流,我看到了一定会回复。

写文章不易,如果你觉得文章对你有帮助,麻烦点一下点赞、收藏,你的支持是我写文章的最大动力!