题目地址:
https://www.lintcode.com/problem/minimum-window-substring/description
给定两个字符串 s s s和 t t t,求 s s s的最短且包含所有 t t t中字符的子串。“包含”的含义是,既要字符都包含,次数也要包含。
更优版本的解参考https://blog.csdn.net/qq_46105170/article/details/109636131。下面介绍一个一般解法。
思路是双指针,并且用一个数组 A A A维护两根指针之间的区间的字符以及其出现次数(这里数组开256长度,每个位置记录这个ASCII码对应的字符出现了多少次,本质上是当成哈希表用的)。接着就是类似于和大于某数的最小子数组的那套方法了,如果发现当前维护的区间的数组 A A A是大于等于 t t t对应的数组 B B B的时候(这里的 A ≥ B A\ge B A≥B的意思是每个位置的数字都相应大于等于,意味着 A A A维护的区间的字符完全包含了 t t t的左右字符),这时候更新答案,并且将左指针右移,直到 A < B A<B A<B,再将右指针右移。如此直到整个字符串遍历完。代码如下:
public class Solution {
/**
* @param source : A string
* @param target: A string
* @return: A string denote the minimum window, return "" if there is no such a string
*/
public String minWindow(String source , String target) {
// write your code here
// 如果是t是空串,则直接返回空串
if (target.isEmpty()) {
return "";
}
// tarCount记录target的每个字符出现的次数,count记录维护的区间里每个字符出现的次数
int[] tarCount = new int[256], count = new int[256];
for (int i = 0; i < target.length(); i++) {
tarCount[target.charAt(i)]++;
}
int minLen = Integer.MAX_VALUE;
String res = "";
for (int j = 0, i = 0; j < source.length(); j++) {
// 将当前字符加上去
count[source.charAt(j)]++;
// 如果维护的区间长度为正,并且包含tarCount,则更新答案,并且右移慢指针
while (i <= j && contains(count, tarCount)) {
// 发现更短子串满足条件,则更新答案
if (j - i + 1 < minLen) {
minLen = j - i + 1;
res = source.substring(i, j + 1);
}
count[source.charAt(i)]--;
i++;
}
}
return res;
}
private boolean contains(int[] count, int[] tarCount) {
for (int i = 0; i < 256; i++) {
if (count[i] < tarCount[i]) {
return false;
}
}
return true;
}
}
时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)。