请朋友们多多指正
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
注意:
- 对于
t中重复字符,我们寻找的子字符串中该字符数量必须不少于t中该字符数量。 - 如果
s中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入: s = "ADOBECODEBANC", t = "ABC"
输出: "BANC"
解释: 最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
1.思路
int res为最终结果,即最小覆盖字串长度
int begin为最终结果起始位置
char[] base = new char[128]
char[] cur = new char[128]
int hitSize == t.length ? 为是窗口字串否包含t的条件
在s中找符合t的子串,明显可以想到用可收缩的滑动窗口法解决
1)怎么确定当前窗口是否包含t,建立一个char[] base = new char[128],遍历t,每个字符出现一次在对应位置+1,再建立一个动态数组cur和hitSize分别表示滑动过程中的字母组合和符合t的总个数,int hitSize == t.length时候即窗口符合包含t的字串,接下来需要把窗口收缩到最小
2)外层循环中右指针不断右移添加元素直到hitSize符合条件,然后内循环左移左指针直到破坏hitSize== t.length 条件(内循环再不破坏hitSize== t.length 条件时候每次都要更新res和begin),此时就记录了本次循环固定右指针后的最小覆盖字串
2.初版(YOLO)
public String minWindow(String s, String t) {
//判断边界,窗口大小最小也是t.length()
if (s.length() < t.length()) {
return "";
}
int minWindowLength = Integer.MAX_VALUE;
int minWindowBegin = 0;
int left = 0;
int right = 0;
char[] base = new char[128];
char[] tmp = new char[128];
int hitSize = 0;
for (int i = 0; i < t.length(); i++) {
base[t.charAt(i)]++;
}
//左闭右开
while(right < s.length()){
//只看在t中的元素
if (base[s.charAt(right)] > 0){
//因为可能出现tmp[s.charAt(right)] >= base[s.charAt(right)]的情况,这时候hitSize不再增加
if (tmp[s.charAt(right)] < base[s.charAt(right)]) {
hitSize++;
}
tmp[s.charAt(right)]++;
}
if (hitSize == t.length()){
while(hitSize == t.length() && left <= right){
//每次进入循环都要最小覆盖字串
minWindowBegin = minWindowLength > (right - left + 1) ? left : minWindowBegin;
minWindowLength = minWindowLength > (right - left + 1) ? (right - left + 1) : minWindowLength;
//收缩左边界,只看在t中的元素
if(base[s.charAt(left)] != 0){
//因为可能出现tmp[s.charAt(right)] >= base[s.charAt(right)]的情况,这时候hitSize不再减少
if (tmp[s.charAt(left)] == base[s.charAt(left)])
hitSize--;
tmp[s.charAt(left)]--;
}
left++;
}
}
right++;
}
return minWindowLength == Integer.MAX_VALUE ? "" : s.substring(minWindowBegin, minWindowBegin + minWindowLength);
}
liweiwei的题解
可以看到li用的是左闭右开区间,其他地方差不太多
public class Solution {
public String minWindow(String s, String t) {
int[] window = new int[128];
int[] pattern = new int[128];
final int A = 'A';
for (Character c : t.toCharArray()) {
pattern[c - A]++;
}
int distance = 0;
for (int i = 0; i < 128; i++) {
if (pattern[i] > 0) {
distance++;
}
}
int sLen = s.length();
int start = 0;
int left = 0;
int right = 0;
int match = 0;
int minLen = sLen + 1;
while (right < sLen) {
Character curChar = s.charAt(right);
if (pattern[curChar - A] > 0) {
window[curChar - A]++;
if (window[curChar - A] == pattern[curChar - A]) {
match++;
}
}
right++;
while (match == distance) {
if (right - left < minLen) {
start = left;
minLen = right - left;
}
// 考虑左边界向右边走
Character leftChar = s.charAt(left);
if (pattern[leftChar - A] > 0) {
window[leftChar - A]--;
if (window[leftChar - A] < pattern[leftChar - A]) {
match--;
}
}
left++;
}
}
return minLen == sLen + 1 ? "" : s.substring(start, start + minLen);
}
}
作者:liweiwei1419
链接:https://leetcode.cn/leetbook/read/learning-algorithms-with-leetcode/x1vsvd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。