如何用最短替换让字符串变平衡?

求解思路

这道题与其考虑"替换哪些字符",不如想"保留哪些字符"。

我们要找的是一个最短的连续子串,这个子串里包含了所有"多余"的字符,只要把这个子串替换掉,剩下的字符串自然就平衡了。

首先统计每种字符的出现次数,如果某个字符出现次数超过了 n/4,那它就是"多余"的,多出来的部分就是"债务";

然后用滑动窗口去找一个最短的子串,这个子串恰好包含了所有这些多余的字符,当窗口内包含的多余字符数量刚好抵消了所有债务时,这个窗口的长度就是答案的候选值,在所有候选值中取最小即可。

代码实现

java 复制代码
public static int balancedString(String str) {
    int n = str.length();
    int[] s = new int[n];
    int[] cnts = new int[4];
    
    // 字符映射并统计频次: Q->0, W->1, E->2, R->3
    for (int i = 0; i < n; i++) {
        char c = str.charAt(i);
        s[i] = c == 'W' ? 1 : (c == 'E' ? 2 : (c == 'R' ? 3 : 0));
        cnts[s[i]]++;
    }
    
    // 计算每种字符的"债务"(多余量)
    int debt = 0;
    for (int i = 0; i < 4; i++) {
        if (cnts[i] < n / 4) {
            cnts[i] = 0;  // 不足的字符无需处理
        } else {
            cnts[i] = n / 4 - cnts[i];  // 转为负数表示多余量
            debt -= cnts[i];  // 累计总债务
        }
    }
    
    // 如果已经平衡,直接返回
    if (debt == 0) {
        return 0;
    }
    
    // 滑动窗口找最短替换子串
    int ans = Integer.MAX_VALUE;
    for (int l = 0, r = 0; r < n; r++) {
        // 右边界扩展,收集多余字符
        if (cnts[s[r]]++ < 0) {
            debt--;
        }
        
        // 债务清零时,尝试收缩左边界
        if (debt == 0) {
            while (cnts[s[l]] > 0) {
                cnts[s[l++]]--;
            }
            ans = Math.min(ans, r - l + 1);
        }
    }
    
    return ans;
}

如果觉得有帮助,欢迎点赞、关注、转发~

相关推荐
.痞老板.1 小时前
java ee--多线程(进阶)
java·java-ee
深入云栈2 小时前
Netty 4.2.x 源码深度解析 (二十三):ByteBuf 核心设计 —— 索引、类型与零拷贝
java·后端·架构
唐墨1232 小时前
linux kernel 比较数据大小的宏定义
linux·算法
爱笑的k113 小时前
nano-vllm 源码剖析:千行 Python 手写离线推理引擎的调度、显存与并行时序
开发语言·python·vllm
拂拉氏3 小时前
【知识讲解-题目讲解】 统计满足K约束的子字符串数量2 (滑动窗口+前缀和+二分查找+分析)
算法·前缀和·二分查找·滑动窗口
wang_shu_mo_ran4 小时前
MyBatis 从入门到进阶(一)
java·spring·mybatis
X1A0RAN4 小时前
PPT 图片批量处理教程:导出全部幻灯片 · 提取全部素材
开发语言·javascript·powerpoint
量化分析码农5 小时前
股票历史数据的复权参数对照:多级别返回的字段与数值差异
java·javascript·后端
猫猫不是喵喵.5 小时前
从0到1创建一个微服务项目
java·数据库·微服务·1024程序员节
熊猫钓鱼>_>5 小时前
普通用户视角的端侧智能体验手记【鸿蒙心迹】
开发语言·人工智能·华为·智能手机·性能优化·ai编程·harmonyos