一道面试高频题:最小覆盖子串的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);
}

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

相关推荐
jiayong2316 小时前
前端面试题库 - 工程化与性能优化篇
前端·面试·性能优化
凯瑟琳.奥古斯特16 小时前
操作系统核心结构解析
java·开发语言·c++·python·职场和发展
June bug16 小时前
【AI赋能测试笔记】5基于文档用例生成系统及skills
笔记·功能测试·职场和发展·测试用例·学习方法
李小狼lee16 小时前
《spring如此简单》第二节--IOC思想的实现,容器是什么
后端·面试
_深海凉_17 小时前
LeetCode热题100-路径总和 III
算法·leetcode·职场和发展
AI人工智能+电脑小能手17 小时前
【大白话说Java面试题 第64题】【JVM篇】第24题:强引用、软引用、弱引用、虚引用分别是什么?
java·开发语言·jvm·面试
怕浪猫17 小时前
小厂三年我现在怎么样了
后端·面试
Purple Coder18 小时前
面试题目总结
面试·职场和发展
小江的记录本18 小时前
【Java基础】Java 8-21新特性 :JDK17:密封类、模式匹配、Record类(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·python·mysql·面试·职场和发展
小江的记录本18 小时前
【Java基础】集合框架: ArrayList vs LinkedList 核心区别、扩容机制(附《思维导图》+《面试高频考点清单》)
java·数据库·python·mysql·spring·面试·maven