• [LeetCode] 76. Minimum Window Substring


    Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "".

    The testcases will be generated such that the answer is unique.

    A substring is a contiguous sequence of characters within the string.

    Example 1:

    Input: s = "ADOBECODEBANC", t = "ABC"
    Output: "BANC"
    Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
    

    Example 2:

    Input: s = "a", t = "a"
    Output: "a"
    Explanation: The entire string s is the minimum window.
    

    Example 3:

    Input: s = "a", t = "aa"
    Output: ""
    Explanation: Both 'a's from t must be included in the window.
    Since the largest window of s only has one 'a', return empty string.

    Constraints:

    • m == s.length
    • n == t.length
    • 1 <= m, n <= 105
    • s and t consist of uppercase and lowercase English letters.

    Follow up: Could you find an algorithm that runs in O(m + n) time?

    最小覆盖子串。

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

    注意:

    对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
    如果 s 中存在这样的子串,我们保证它是唯一的答案。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/minimum-window-substring
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    思路依然是滑动窗口(sliding window),这个题解是具有普适性的,可以套用到多个LC的题目中。如下是几个细节,

    • 创建一个hashmap,记录T中出现的字母及其次数
    • 创建一个变量count去记录T的长度
    • 创建两个指针left和right,一前一后扫描S,right在前,left在后,去卡S里面的子串,看这个子串里面是否包含T中所有的字符
    • 最后跳出循环的条件是right已经扫描完整个S的长度

    扫描的一开始,是 right 指针往前走,每遇到一个字符,无论他在不在T中,就都去map中--这个字符;如果这个字符在T中也有,同时也要去count--。当 count == 0 的时候,证明此时的子串已经包含了T中所有的字母了,可以考虑缩减 start 和 end 之间的距离了。缩减的条件是 while (count == 0),去看 end - start 是否能缩短那个最小长度 minLen,同时开始挪动 start 指针;若能缩短,也要记录一个变量 minStart,这样就能记住最短的子串到底从什么位置开始的。挪动 start 指针的时候也要去 map 中补足当前遍历到的字符的出现次数。如果当前字符在 map 中的 value 大于 0 了,count 也需要++,因为这说明有一个字符已经不在子串中了,此时会跳出 while 循环。最后最短子串是 s.substring(minStart, minStart + minLen)。

    时间O(n)

    空间O(1) - 128位的array几乎可以忽略不计

    Java实现

     1 class Solution {
     2     public String minWindow(String s, String t) {
     3         int[] map = new int[128];
     4         for (char c : t.toCharArray()) {
     5             map[c]++;
     6         }
     7         // end指针在右边,start指针在左边
     8         int start = 0;
     9         int end = 0;
    10         // 最短子串的起点
    11         int minStart = 0;
    12         // 最短子串的长度
    13         int minLen = Integer.MAX_VALUE;
    14         int counter = t.length();
    15         while (end < s.length()) {
    16             char c1 = s.charAt(end);
    17             if (map[c1] > 0) {
    18                 counter--;
    19             }
    20             map[c1]--;
    21             end++;
    22             // 如果找到了所有t中的字符,可以试着缩小窗口的距离了
    23             while (counter == 0) {
    24                 // 试图更新最短子串的长度和起点
    25                 if (minLen > end - start) {
    26                     minLen = end - start;
    27                     minStart = start;
    28                 }
    29                 char c2 = s.charAt(start);
    30                 map[c2]++;
    31                 start++;
    32                 if (map[c2] > 0) {
    33                     counter++;
    34                 }
    35             }
    36         }
    37         return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen);
    38     }
    39 }

    JavaScript实现

     1 /**
     2  * @param {string} s
     3  * @param {string} t
     4  * @return {string}
     5  */
     6 var minWindow = function (s, t) {
     7     let ans = '';
     8     // save all the letters in t to a hashmap
     9     let map = {};
    10     t.split('').forEach(ch => map[ch] = (map[ch] || 0) + 1);
    11     let count = Object.keys(map).length;
    12 
    13     // traverse s
    14     let l = 0;
    15     let r = -1;
    16     while (r < s.length) {
    17         if (count === 0) {
    18             // l~r contains t
    19             if (!ans || r - l + 1 < ans.length) {
    20                 ans = s.slice(l, r + 1);
    21             }
    22             // get rid of curr ch and then move l
    23             if (map[s[l]] !== undefined) {
    24                 map[s[l]]++;
    25             }
    26             if (map[s[l]] > 0) {
    27                 count++;
    28             }
    29             l++;
    30         } else {
    31             // l~r doesn't contain t
    32             // move r and add new ch
    33             r++;
    34             if (map[s[r]] !== undefined) {
    35                 map[s[r]]--;
    36             }
    37             if (map[s[r]] === 0) {
    38                 count--;
    39             }
    40         }
    41     }
    42     return ans;
    43 };

    sliding window相关题目

    LeetCode 题目总结

  • 相关阅读:
    Javascript实现局部刷新
    Javascript模块化开发-轻巧自制
    javascript面向对象实例
    Javascript兼容和CSS兼容总结
    隐藏关机按钮
    数组排序
    常用数组获取最新和第一个元素值
    php 操作redis 以及几个常用命令
    git 常用命令
    JSON.parse和JSON.stringify的区别
  • 原文地址:https://www.cnblogs.com/cnoodle/p/12624255.html
Copyright © 2020-2023  润新知