问题
Minimum Window Substring Hard
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.lengthn == t.length1 <= m, n <= 105sandtconsist of uppercase and lowercase English letters.
Follow up: Could you find an algorithm that runs in O(m + n) time?
解题思路
题中要求最好使用O(m + n)的时间复杂度来解决,所以Brute Force是行不通的。那么问题就来了,如何将嵌套循环优化为一次遍历?
这时候就该滑动窗口算法闪亮登场了。这个算法适合用来解决字符串/数组的子元素问题,可用来降低时间复杂度。抽象地说,整个字符串好比一个长长的推拉窗口,而这个窗口中间有两扇可移动的玻璃窗,我们可以这样做:
- 将一扇窗(右窗)从左端往右端移动
- 满足一定条件后,暂停移动右窗,将左窗从左端往右端移动
- 满足一定条件后,暂停移动左窗
- 重复上面的步骤,直到两扇窗移动到右边
回到本题, s 就是我们需要遍历的推拉窗,随着右窗的移动遍历 s 中的字符,暂停右窗的条件就是 t 中的字符都已出现,随着左窗移动,将 s 中的字符丢弃,当丢弃了 t 中的字符时,暂停左窗,继续右窗移动。
解题的关键在于
- 对字符串
t建模,用数组或Map表示t中字符和出现的次数 - 遍历
s时,当出现t中字符是,上述数组或Map的元素值-1,当计算后的元素值仍大于等于零时,表示有效计数 - 用计数器cnt表示
t中字符在s中出现的有效次数,当cnt==t.length时表示t中字符都已出现 t中字符都已出现后,开始移动左窗
参考答案
public String minWindow(String s, String t) {
// 128 characters in ASCII
int[] charCnt = new int[128];
int left = 0;
int foundCharCnt = 0;
int minLeft = -1;
int minLen = Integer.MAX_VALUE;
// loop t, charCnt++ when char appears in t
for (char c : t.toCharArray()) {
++charCnt[c];
}
// loop s
for (int right = 0; right < s.length(); ++right) {
// charCnt-- for each char, when char is in t (--charCnt >= 0) foundCharCnt++
if (--charCnt[s.charAt(right)] >= 0) {
foundCharCnt++;
}
// when all chars in t have been found (foundCharCnt == t.length())
while (foundCharCnt == t.length()) {
// record the minLen and minLeft
if (minLen > right - left + 1) {
minLen = right - left + 1;
minLeft = left;
}
// if char at pointer left is in t (++charCnt > 0), foundCharCnt--
if (++charCnt[s.charAt(left)] > 0) {
foundCharCnt--;
}
// shrink left pointer
left++;
}
}
return minLeft == -1 ? "" : s.substring(minLeft, minLeft + minLen);
}
拓展训练
Given an array of integers of size ‘n’. Our aim is to calculate the maximum sum of ‘k’ consecutive elements in the array.
Input : arr[] = {100, 200, 300, 400}
k = 2
Output : 700
Input : arr[] = {1, 4, 2, 10, 23, 3, 1, 0, 20}
k = 4
Output : 39
We get maximum sum by adding subarray {4, 2, 10, 23}
of size 4.
Input : arr[] = {2, 3}
k = 3
Output : Invalid
There is no subarray of size 3 as size of whole
array is 2.
详细解答参考下方资料链接
到作者的LeetCode专栏中看看,有没有其他感兴趣的问题吧!