一道面试高频题:最小覆盖子串的O(n)解法

求解思路

这道题我们可以把问题想象成"欠债还债"的过程:

一开始我们欠目标字符串 tar 中所有字符的债,然后用一个窗口在源字符串 str 上滑动,不断"还债"。

具体来说,我们用右指针 r 不断向右扩展窗口来收集字符还债,当债务全部还清时(也就是窗口已经包含了 tar 的所有字符),我们就尝试收缩左边界 l 来让这个窗口尽可能小,把那些"多给的"字符收回来。

在这个过程中,我们记录下遇到的最小窗口的位置和长度,最后返回这个最小窗口对应的子串就是答案。

举个栗子

假设 str = "ADOBECODEBANC", tar = "ABC":

  1. 右指针扩展到 ADOBEC 时,debt 首次归零
  2. 左指针收缩,去掉 ADO,得到 BANC
  3. 继续右移,在 CODEBA 时再次覆盖
  4. 收缩后得到 BA,但不满足(缺C)
  5. 最终确定最小窗口是 BANC

代码实现

java 复制代码
public static String minWindow(String str, String tar) {
    if (str.length() < tar.length()) {
        return "";
    }
    char[] s = str.toCharArray();
    char[] t = tar.toCharArray();
    int[] cnts = new int[256];
    
    // 初始化欠债表:tar中的字符都标记为负数(欠债)
    for (char cha : t) {
        cnts[cha]--;
    }
    
    int len = Integer.MAX_VALUE;  // 最小覆盖子串的长度
    int start = 0;                // 最小覆盖子串的起始位置
    
    for (int l = 0, r = 0, debt = t.length; r < s.length; r++) {
        // 当前字符s[r]进入窗口,还债
        if (cnts[s[r]]++ < 0) {
            debt--;  // 只有真正需要的字符才能减少债务
        }
        
        if (debt == 0) {
            // 债务还清,找到了一个覆盖子串
            // 尝试收缩左边界,去掉多余字符
            while (cnts[s[l]] > 0) {
                cnts[s[l++]]--;
            }
            
            // 更新最小窗口
            if (r - l + 1 < len) {
                len = r - l + 1;
                start = l;
            }
        }
    }
    
    return len == Integer.MAX_VALUE ? "" : str.substring(start, start + len);
}

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

相关推荐
Ruihong5 小时前
Vue withDefaults 转 React:VuReact 怎么处理?
vue.js·react.js·面试
kyriewen6 小时前
别再这样写 async/await 了:我在 Code Review 中见过最多的 8 个错误
前端·javascript·面试
烬羽11 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
云技纵横11 小时前
一个 @Async,把 @Transactional 的事务边界打穿了
后端·面试
想要成为糕糕手11 小时前
Harness Engineering:大模型时代的“马鞍”——从记忆层开始,让AI真正为你所用
面试·ai编程·claude
kyriewen1 天前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
她的男孩1 天前
后台接口加密别只会 HTTPS,ForgeAdmin 的 RSA + SM4/AES 源码拆解
后端·面试·开源
Randyliu1 天前
20260508-Agent搭建记录以及对ReAct框架的理解
面试·agent
ZzT1 天前
公司用 AI 筛简历,他写了个 AI 帮你挑公司
面试·aigc·ai编程
PBitW1 天前
GPT训练我的第四天,被打惨了!!!😭😭😭
前端·javascript·面试