[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 题目总结

posted @ 2020-04-03 07:02  CNoodle  阅读(558)  评论(0编辑  收藏  举报