LeetCode 76.最小覆盖字串---Java题解

本文介绍了一种使用滑动窗口和need数组优化的算法,解决给定字符串S中找到子串T所有字符的最小子串问题。通过维护字符出现次数,快速确定左右边界,确保在O(n)时间复杂度内完成查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。

示例:

输入:S = "ADOBECODEBANC", T = "ABC"
输出:"BANC"

提示:

  • 如果 S 中不存这样的子串,则返回空字符串 “”。
  • 如果 S 中存在这样的子串,保证它是唯一的答案。

题解:
滑动窗口思想
用i,j来表示当前滑动窗口的左边界和右边界,当当前的滑动窗口包含T的时候,记录长度,并在这些长度中取最小长度即可

具体步骤

  1. 通过增大j的值,使窗口向右扩大直到包含T的所有字符
  2. 通过增大i的值,使窗口左侧不断缩小直到窗口最左侧为T中的某个字符(也就是不能再缩小了)
  3. 这时i,j之间的字符串就对应了一个解,和之前保存的长度比较,选择最小值
  4. 使左侧窗口右移一位(i++),这时滑动窗口字符串不满足条件了,返回执行1

在整个步骤执行过程中,最难的就是如何确定右边界(j指针)扩大到刚好包含了T中所有字符,左边界(i指针)缩小到刚好不能再缩小

在这里我通过need数组来记录,need数组的下标表示字符的ASCII码值,而对应的值为字符出现次数,首先我们要用T字符串来初始化这个数组,在滑动窗口每滑动一次,我们都要去维护这个need。指针每此移动,我们都让当前指针指向的元素对应need中数值减一。

通过这个need便解决了这两个问题,
右边界的停止条件:need中下标为T中字符的所有对应值都为0,在这里我们可以用count来等效,也就是用count来记录总个数(T的长度),当count==0时也就代表need中相应字符下标对应的值都为0了。

左边界的停止条件:在右边界停止以后,我们要缩小左边界,也就是i++,可以想到对于多余的元素,在need中对应的值是都为负数的(因为除了初始化的字符外,其余的默认都为0,一但遇到了,减一后就为负数了),所以如果判定当前字符在need中的值为负数,那左边界就要右移缩小,直到等于0,就不能再缩小。

代码:

class Solution {
    public String minWindow(String s, String t) {
        if(s==null||s.length()==0||t==null||t.length()==0)
            return "";
		
        int[] need=new int[128];

        int l=0,r=0;//左边界和右边界初始化
        int count=t.length();//也就是总数量
        int start=0;//记录得到的字符串的左边界
        int size=Integer.MAX_VALUE;//记录得到的字符串长度

        for(int i=0;i<t.length();i++)//初始化need数组
            need[t.charAt(i)]++;

        while(r<s.length()){//右移开始
            char c=s.charAt(r);
            if(need[c]>0)//找到有效字符,总数量减一
                count--;

            need[c]--;//对应元素数量减一
            if(count==0){//此时停止右边界继续右移
            	//开始缩小左边界
                while(need[s.charAt(l)]<0){
                    need[s.charAt(l)]++;//释放左边移动出窗口的字符
                    l++;//指针右移
                }

                if(r-l+1<size){//更新最优解
                    start=l;//记录字符串开始下标
                    size=r-l+1;//记录长度
                }
				
				//左指针右移,使窗口不满足条件重新开始循环
                need[s.charAt(l)]++;
                l++;
                count++;
            }

            r++;
        }

        return size==Integer.MAX_VALUE?"":s.substring(start,start+size);
    }
}

小白一枚,还望大佬们多多指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值