LeetCode 76.最小覆盖子串

题目:

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。

思路:

  • 本题所采用方法为滑动窗口,即设置两个指针left和right来表示当前窗口的左右界限,我们可以设置一个need数组,索引代表字符,索引在数组中的值代表还需要几个当前字符才能符合t的标准
  • 第一步:每次先移动right指针,碰到一个值就让need[s.charAt(right)]--,如果当前字符存在于目标字符串t中,那么也让sum--,直到sum==0 ,此时说明当前滑动窗口已经包含了所有目标字符串t
  • 第二步:第一步走完之后,就该移动left指针了,因为刚才right指针走过的位置中可能存在不需要的字符,通过移动left指针可以缩小当前滑动窗口的范围,直到碰到第一个在字符串t中出现的字符,这时的一个最小滑动窗口区间就出现了,但他并不一定是最终结果,因为后面可能还会存在比当前滑动窗口区间还要小的情况
  • 第三步:将第二步找到的第一个存在于目标串t中的字符从need数组中剔除(need[s.charAt(left)]++,表示当前滑动窗口还需要这个字符),并继续移动right指针重复刚才的第一步,直到right指针走到s字符串的最后,这样整个字符串的最优结果就出现了

以下为代码+注释:

	public String minWindow(String s, String t) {
        // 滑动窗口
        // 首先设置一个need[]数组,索引为字符的int类型,数值代表需要几个该字符
        int[] need = new int[128];
        int slen = s.length();
        int tlen = t.length();
        // 先将目标字符串t遍历一遍,将需要的字符在need数组中更新相应的值
        // 这样如果need数组中的值都小于等于0了,就说明当前窗口已经将需要的东西包含完了,没有需要的字符了
        for(int i = 0; i < tlen; i++){
            need[t.charAt(i)]++;
        }
        // 第一步:设置两个指针,首先移动右指针,并维护一个sum表示需要的字母总和,
        // 每碰到一个需要的字符,就将need中对应字符的值--,并将sum--,如果sum为0,说明不需要字母了,当前滑动窗口已经包含t的所有字母
        // 第二步:这个时候就要移动左指针,因为左边区域可能有很多不需要的字母,我们需要将他们删除来求出最小的滑动窗口大小,并设置一个start
        // 第三步:根据start索引以及size大小截取并返回最终结果,size表示最小包含所有t中字母的滑动窗口大小,start代表该情况下滑动窗口的第一个索引位置
        int left = 0, right = 0, sum = tlen, size = Integer.MAX_VALUE, start = 0;
        while(right < slen){
            // 如果该字母恰好是需要的字母,就将sum--,也就是还需要查找的字母数量--
            if(need[s.charAt(right)] > 0){
                sum--;
            }
            // 不管该字母是否需要,都要将它对应的need数组--
            need[s.charAt(right)]--;
            // 如果sum为0,说明t中所有字母都包含了,这时就要移动左指针了
            if(sum == 0){
                while(left < right && need[s.charAt(left)] < 0){
                    need[s.charAt(left)]++;
                    left++;
                }
                // 走到这,说明走到了第一个need值为0的地方(因为不存在于t中的字母经过right指针向右移动时的--,他们的need对应值肯定是小于0的),也就是第一个在t中存在的字母
                // 那么就要将当前情况下的滑动窗口大小和size也就是记录大小作比较,如果这个更小,那么就进行更新
                if(right - left + 1 < size){
                    // 同时更新size,并将开始索引start置为第一个目标字母所在索引
                    size = right - left + 1;
                    start = left;
                }
                // 然后将第一个目标字母从华东窗口中剔除,也就是将该字母对应的need值加1,说明滑动窗口中还需要该字母,进行下一个新的滑动窗口的寻找
                need[s.charAt(left)]++;
                sum++;
                left++;
            }
            right++;
        }
        // 如果size为默认初始值,说明就没有符合条件的滑动窗口,返回空串,否则,返回以start索引开头的最小串
        return size == Integer.MAX_VALUE ? "" : s.substring(start, start + size);
    }

笔者也在不断学习,如有错误,欢迎指正!

上一篇:need


下一篇:JavaScript雷区:使用[]引用对象必须加双引号