最小覆盖子串(Leetcode76)

例题:
分析:

比如现在有字符串(s),s = "ADOBECODEBANC", 给出目标字符串 t = "ABC", 题目就是要从原始字符串(s)中找到一个子串(res)可以覆盖目标字符串 t ,子串 "BANC"恰能覆盖 字符串t ,且长度最短,符合题目要求。

我们可以结合下图来分析:

先定义两个变量i,j,一开始,i 和 j 都指向原始字符串的0索引处,看看此时 i ~ j 范围内的字符串是否满足目标字符串(t),如果不满足,则 j 指针往后移动(j++),i 指针先不动,扩大 i ~ j 的范围,直至i ~ j 范围内的字符串满足目标字符串(t),此时记录i 和 j 的位置。 然后 j 指针不动,i++,在满足目标字符串的情况下不断缩小范围,找到最小覆盖子串。

核心思想:

1.统计目标串需要的各种字符个数,统计原始串 i ~ j 范围内各种字符个数。

2.如果原始串 i ~ j 范围内不满足条件,j++ 扩大范围,直到满足条件 j 停下来。

3.一旦满足条件 i++ 缩小范围,直到再次不满足条件。

4.重复 2、3 两步 直至 j 到达原始串末尾。

代码实现:
java 复制代码
public class MinWindowLeetcode76 {

    /*
    * 1.统计目标串需要的各种字符个数,统计原始串i~j范围内各种字符个数
    * 2.如果原始串i~j范围内不满足条件,j++扩大范围,直到满足条件j停下来
    * 3.一旦满足条件,i++缩小范围,直到再次不满足条件
    * 4.重复2、3两步,直至j到达原始串末尾
    * */
    //定义一个结果类,用来记录最小覆盖子串的左右边界
    static class Result{
        int i;
        int j;

        public Result(int i, int j) {
            this.i = i;
            this.j = j;
        }
    }
    public static String minWindow(String s, String t) {
        //统计目标字符串中各种字符个数
        char[] target = t.toCharArray();
        int[] targetCount = new int[128];   //因为题目说了给出的目标字符串是英文字母(大小写都有),128位足矣
        int passTotal = 0;  //需要满足的条件,目标字符串中的一个字符代表一个条件
        for (char ch : target) {
            targetCount[ch]++;
        }
        for (int count : targetCount) {
            if(count > 0){
                passTotal++;
            }
        }
        //统计原始字符串i~j中各种字符个数
        char[] source = s.toCharArray();
        int[] sourceCount = new int[128];
        int i = 0;
        int j = 0;
        int passed = 0; //已经通过的条件个数
        Result res = null;
        while(j < source.length){
            //扩大 j 范围,更新范围内字符计数 和 通过条件数
            char right = source[j];
            sourceCount[right]++;
            if(sourceCount[right] == targetCount[right]){
                passed++;
            }
            //表示已经找到一个覆盖子串,缩小 i 范围,j停止,i++,同时改变通过条件数
            while(passed == passTotal && i <= j){
                if(res == null){
                    res = new Result(i, j);
                }else{
                    if(j - i < res.j - res.i){
                        res = new Result(i, j);
                    }
                }
                char left = source[i];
                sourceCount[left]--;
                if(sourceCount[left] < targetCount[left]){
                    passed--;
                }
                i++;
            }
            j++;
        }
        return res == null ? "" : new String(source, res.i, res.j - res.i + 1);
    }

    public static void main(String[] args) {
        System.out.println(minWindow("ADOBECODEBANC", "ABC")); // BANC
        //System.out.println(minWindow("aaabbbbbcdd", "abcdd")); // abbbbbcdd
    }
}
相关推荐
sheeta199836 分钟前
LeetCode 每日一题笔记 日期:2025.11.24 题目:1018. 可被5整除的二进制前缀
笔记·算法·leetcode
一只会写代码的猫2 小时前
面向高性能计算与网络服务的C++微内核架构设计与多线程优化实践探索与经验分享
java·开发语言·jvm
萤丰信息3 小时前
智慧园区能源革命:从“耗电黑洞”到零碳样本的蜕变
java·大数据·人工智能·科技·安全·能源·智慧园区
曹牧3 小时前
Eclipse为方法添加注释
java·ide·eclipse
我叫张小白。4 小时前
Spring Boot拦截器详解:实现统一的JWT认证
java·spring boot·web·jwt·拦截器·interceptor
Gerardisite6 小时前
如何在微信个人号开发中有效管理API接口?
java·开发语言·python·微信·php
gfdhy6 小时前
【c++】哈希算法深度解析:实现、核心作用与工业级应用
c语言·开发语言·c++·算法·密码学·哈希算法·哈希
闲人编程7 小时前
Python的导入系统:模块查找、加载和缓存机制
java·python·缓存·加载器·codecapsule·查找器
百***06017 小时前
SpringMVC 请求参数接收
前端·javascript·算法
故渊ZY7 小时前
Java 代理模式:从原理到实战的全方位解析
java·开发语言·架构