题解一:
双指针滑动窗口:暴力解法——用双指针来表示字符串s中的子串首尾,遍历所有子串并与字符串t判断是否符合条件。我们可以对遍历和判断的过程进行优化,首先是遍历,右指针先移动直到涵盖所以需要的字母,左指针再移动删除不需要的字母,也就是窗口扩展时寻找可行解,窗口收缩时优化可行解。循环这个过程,找出所有符合条件的子串,比较出最短的子串。
然后是判断,维护一个数组,数组下标表示字母,数组内容表示当前滑动窗口下,我们还需要的字母数量。当数组均小于等于0时,代表已经涵盖了所有需要的字母。数组中小于等于0的值的数目可以另外用一个整型来表示。
class Solution {
public String minWindow(String s, String t) {
int need[] = new int[128];//维护需要的字母及个数
int diff = 0;//维护need数组中大于0的值
int shortest = 0x3f3f3f3f;//存储最短子串长度
int resultLeft = 0;//存储结果子串左下标
int resultRight = 0;//存储结果子串右下标
for (int i = 0; i < t.length(); i++) {//初始化need数组
need[t.charAt(i)]++;
}
for (int i = 0; i < need.length; i++) {//初始化diff
if (need[i] > 0) diff++;
}
for (int left = 0, right = 0; right < s.length(); ) {
while (right < s.length()) {//右指针移动,寻找可行解
need[s.charAt(right)]--;
if (need[s.charAt(right)] == 0) diff--;
right++;
if (diff == 0) break;
}
while (left < right) {//左指针移动,优化可行解
if (need[s.charAt(left)] + 1 > 0) break;
else need[s.charAt(left)]++;
left++;
}
if (diff == 0 && shortest > right - left) {//判断子串最短
shortest = right - left;
resultRight = right;
resultLeft = left;
}
}
if (shortest == 0x3f3f3f3f) return "";//返回最短子串
else return s.substring(resultLeft, resultRight);
}
}