最小覆盖子串(Java详解)

这篇具有很好参考价值的文章主要介绍了最小覆盖子串(Java详解)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、题目描述

二、题解


一、题目描述

给定两个字符串 s 和 t 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串,则返回空字符串 "" 。

如果 s 中存在多个符合条件的子字符串,返回任意一个。

注意: 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。

示例:

输入:s = "ADOBECODEBANC", t = "ABC"

输出:"BANC"

输入:s = "a", t = "a"

输出:"a"

二、题解

思路分析:题目要求我们找到 s 中包含 t 的所有字符的最短子字符串,即找到的子串中必须含有 t 中所有字符,可以有其他字符,返回其中最短的子串。

首先,我们很容易想到可以通过暴力枚举的方式来找到最小覆盖子串

最小覆盖子串(Java详解),Java刷题,数据结构,java,双指针,算法

每次记录子串的长度,并更新记录的最短子串,当i 遍历完 s 时,找到最小子串,由于当 i 找到 t 中字符时,要使用 j 向后遍历,找到子串,因此,暴力枚举的时间复杂度为O() ,

当找到子串时,i 向后移动,直到再次找到 t 中字符,此时再向后寻找子串,

当再次向后寻找子串时,j可能向后移动,也可能保持不动

 最小覆盖子串(Java详解),Java刷题,数据结构,java,双指针,算法

因此,我们可以不用每次找到 t 中字符时,都从当前下一位置向后寻找,只需从 j 上次记录的位置开始向后寻找

此时,我们可以考虑使用滑动窗口来解决本题,即使用left 和 right 两个指针维护一个窗口,窗口中不包含 t 中所有字符时,right向右滑动,添加新的字符,当窗口中包含 t 中所有字符时,判断并更新最小子串,再将left 向右滑动,移除左边元素

最小覆盖子串(Java详解),Java刷题,数据结构,java,双指针,算法

解题步骤:

1. 使用哈希表记录 t 中字符的种类和个数

2. 定义left 和 right 指针遍历s,并维护窗口

3. 当窗口中不含有 t 中所有字符时,向右移动 right ,添加新的字符;

当窗口中含有 t 中所有字符时,判断并更新最小子串,再向右移动 left ,直到移除t中的一个字符

再分析清楚过程后,我们可以尝试编写代码来解决本题

首先我们使用哈希表统计字符的种类和长度:

//1. 
//特殊情况:若s的长度小于t,直接返回空字符串
if(s.length() < t.length()){
    return "";
}
//使用哈希表统计t中字符的种类和长度
//由于题目中给出s和t由英文字母组成,因此我们可以使用数组模拟哈希表
int[] hash1 = new int[128];
//记录t中字符的种类和数量
for (int i = 0; i < t.length(); i++) {
    hash1[t.charAt(i)]++;
}

 接下来我们遍历s并维护窗口:

//2. 
int begin = -1, minLen = -1;//记录最小子串的起始位置和长度
int[] hash2 = new int[128];//记录s中字符的种类和个数

//使用left和right维护窗口
for (int left = 0,right = 0; right < s.length(); right++) {
    //右边字符进窗口
    char in = s.charAt(right);
    hash2[in]++;

    //判断是否需要出窗口
    
        //更新结果
        //左边元素出窗口
        
        

    }
}

如何判断是否需要出窗口?

当子串包含t中所有字符时,需要出窗口。由于我们使用数组来模拟哈希表,我们可以通过遍历的方式来判断hash2中是否包含hash1中所有字符,然而,这种方式效率较低,那么我们该如何改进呢?

我们可以使用变量 count 来统计子串中有效字符(当前字符ch为 t 中字符,且此时窗口中ch的数量 小于等于 t 中 ch个数的个数。此时,在判断出窗口时,仅需判断count 是否 大于等于 t 的长度,若大于,则出窗口

使用count来标记子串中所含有的 t 中字符个数

最小覆盖子串(Java详解),Java刷题,数据结构,java,双指针,算法

 注意,当前字符为 t 中字符,也可能不为有效字符,例如:

最小覆盖子串(Java详解),Java刷题,数据结构,java,双指针,算法

此时,虽然A为t中字符,但窗口中A的个数大于 t 中A的个数,此时的字符A不能判断为有效字符

//2.
int begin = -1, minLen = -1;//记录最小子串的起始位置和长度
int[] hash2 = new int[128];//记录s中字符的种类和个数
//使用left和right维护窗口
int count = 0;//记录窗口中有效字符的个数
for (int left = 0,right = 0; right < s.length(); right++) {
    //右边字符进窗口
    char in = s.charAt(right);
    hash2[in]++;
    //判断是否是有效字符
    //先将字符放入哈希表后,再判断
    if(hash2[in] <= hash1[in]){
        count++;
    }

    //判断是否需要出窗口
    //出窗口的条件:当有效字符的个数大于等于t的长度
    while (count >= t.length()){
        //更新结果
        if(right - left + 1 < minLen || begin == -1){
            begin = left;
            minLen = right - left + 1;
        }
        //将左边元素出窗口
        char out = s.charAt(left);
        //判断是否是有效字符出窗口
        //先判断当前字符是否是有效字符后,再出窗口
        if(hash2[out]-- <= hash1[out]){
            count--;
        }
        //左边元素出窗口
        left++;
    }
}

最后,再返回最小覆盖子串即可

完整代码:

class Solution {
    public String minWindow(String s, String t) {
       //1.
        //特殊情况:若s的长度小于t,直接返回空字符串
        if(s.length() < t.length()){
            return "";
        }
        //使用哈希表统计t中字符的种类和长度
        //由于题目中给出s和t有英文字母组成,因此我们可以使用数组模拟哈希表
        int[] hash1 = new int[128];
        //记录t中字符的种类和数量
        for (int i = 0; i < t.length(); i++) {
            hash1[t.charAt(i)]++;
        }
        
        //2.
        int begin = -1, minLen = -1;//记录最小子串的起始位置和长度
        int[] hash2 = new int[128];//记录s中字符的种类和个数
        //使用left和right维护窗口
        int count = 0;//记录窗口中有效字符的个数
        for (int left = 0,right = 0; right < s.length(); right++) {
            //右边字符进窗口
            char in = s.charAt(right);
            //判断是否是有效字符
            //先将字符放入哈希表后,再判断
            if(++hash2[in] <= hash1[in]){
                count++;
            }

            //判断是否需要出窗口
            //出窗口的条件:当有效字符的个数大于等于t的长度
            while (count >= t.length()){
                //更新结果
                if(right - left + 1 < minLen || begin == -1){
                    begin = left;
                    minLen = right - left + 1;
                }
                //将左边元素出窗口
                char out = s.charAt(left);
                //判断是否是有效字符出窗口
                //先判断当前字符是否是有效字符后,再出窗口
                if(hash2[out]-- <= hash1[out]){
                    count--;
                }
                //左边元素出窗口
                left++;
            }
        }
        //遍历完成 返回最小子串
        return begin == -1 ? "": s.substring(begin,begin+minLen);
    }
}

题目来自:

LCR 017. 最小覆盖子串 - 力扣(LeetCode)文章来源地址https://www.toymoban.com/news/detail-770500.html

到了这里,关于最小覆盖子串(Java详解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java高阶数据结构 & 并查集 & 最小生成树

    并查集与最小生成树 1.1 并查集的原理 在一些应用问题中,我们常常会遇到一类问题 一开始是一个人 后来新增的人可能与这个人有关系,也可能与这个人无关系。 一个人与一个人有关系,这个人与另一个人也有关系,那么三人都有关系。 有关系的和没关系的之间是不同的类

    2024年02月03日
    浏览(42)
  • java数据结构与算法刷题-----LeetCode283. 移动零

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 双指针,用right和left两个指针,将非0元素,全部按顺序换到数组前面。left指向左边非0元素应该插入的位置,right找到非

    2024年01月21日
    浏览(49)
  • java数据结构与算法刷题-----LeetCode566. 重塑矩阵

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 代码:时间复杂度O(r*c).除题目要求外,算法本身没有需要额外空间,空间复杂度O(1) 从0开始算,一个3列n行矩阵中,每行就有3个元

    2024年01月21日
    浏览(46)
  • 0302Prim算法-最小生成树-图-数据结构和算法(Java)

    1.1 概述 1.1.1 算法描述 算法描述: 初始化最小生成树,只有一个起点; 每次将下一条连接树中顶点和其补集中顶点且权重最小的边(黑色表示)加入树中; 重复步骤中2,直至最小生成树中加入了V-1条边。 命题L。Prim算法能够得到任意加权连通图的最小生成树。 证明:有命

    2023年04月16日
    浏览(42)
  • java数据结构与算法刷题-----LeetCode287. 寻找重复数

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 弗洛伊德判圈法,也就是快慢指针判圈法(龟兔赛跑算法),此算法分为两个步骤 判断是否有环,并得到快慢指针相遇

    2024年01月24日
    浏览(43)
  • 数据结构(Java)最小生成树(普里姆、克鲁斯卡尔算法)

    最小生成树 (Minimum Cost Spanning Tree) ,简称 MST 。 1) 给定一个带权的无向连通图 , 如何选取一棵生成树 , 使树上所有 边上权的总和为最小 ,就 叫最小生成树 2) N 个顶点,一定有 N-1 条边 3) 包含全部顶点 4) N-1 条边都在图中 (好像不能形成闭合回路) 求最小生成树的算法主要是

    2023年04月08日
    浏览(42)
  • java数据结构与算法刷题-----LeetCode766. 托普利茨矩阵

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 这道题只要换一种理解方式,瞬间就会变的很简单。 题目描述是每个元素左上和右下对角线元素都相同。但是,我们发

    2024年01月25日
    浏览(48)
  • java数据结构与算法刷题-----LeetCode667. 优美的排列 II

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 题目要求我们返回一个数组长度为n的数组,必须含有1~n的所有数,并且从左到右,相邻的元素依次相减,它们的差,必

    2024年01月25日
    浏览(52)
  • java数据结构与算法刷题-----LeetCode240. 搜索二维矩阵 II

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 法一:把整个数组遍历一遍,时间复杂度O(m*n) 法二:每一行用二分搜索,那么时间复杂度就是O(m * l o g 2 n log_2{n} l o g

    2024年01月22日
    浏览(61)
  • java数据结构与算法刷题-----LeetCode96. 不同的二叉搜索树

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难,但它就是固定套路而已。其实动态规划只不过是将多余的步骤,提前放到dp数组中(就是一个数组,只

    2024年01月21日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包