时间复杂度O(n)查找最小覆盖子串
题目:给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
用暴力解法的时间复杂度是O(n^2),我这里使用滑动窗口法实现的时间复杂度是O(n)
核心思路:滑动窗口(双指针) 结合 哈希表。通过维护一个动态窗口(由左右指针界定),逐步扩大和缩小窗口以寻找满足条件的最小子串。
- 统计目标字符需求:用哈希表 tmap 记录 t 中每个字符的出现次数(键为字符,值为次数),并记录 t 中不同字符的种类数。
- 维护窗口字符统计:用哈希表 smap 记录当前窗口中每个字符的出现次数。
- 动态调整窗口:
移动右指针扩大窗口,直到窗口包含 t 中所有字符(且数量满足需求)。
当窗口满足条件时,移动左指针缩小窗口,尝试在保持条件的前提下找到更小的子串。 - 判断窗口有效性:用变量 valid 记录窗口中满足要求的字符种类数,当 valid 等于 t 的字符种类数时,窗口有效。
class Solution {
public String minWindow(String s, String t) {
Map<Character, Integer> smap = new HashMap<>(); //当前窗口
Map<Character, Integer> tmap = new HashMap<>();
int left = 0, right = 0; // 左右指针
int valid = 0; // 满足频率条件的字符数量(统计有效字符),比如当smap中A的数量达到3个时,valid才会把A当做有效字符,valid加一
int start = 0, minLen = Integer.MAX_VALUE; // 最小子串的起始位置和长度
int slength = s.length();
// 处理边界情况
if (s == null || t == null || s.length() == 0 || t.length() == 0 || s.length() < t.length()) {
return "";
}
// 统计t中每个字符出现的次数
for (char c : t.toCharArray()) {
tmap.put(c, tmap.getOrDefault(c, 0) + 1);
}
int tmap_size = tmap.size(); // t中字符种类数
/**
遍历s字符串
*/
while (right < slength) {
char c = s.charAt(right);
// 判断是不是目标字符
if (tmap.containsKey(c)) {
smap.put(c, smap.getOrDefault(c, 0) + 1); //更新目标字符的频率
if (smap.get(c).intValue() == tmap.get(c).intValue()) { // 如果频率相同了,成为有效字符,加入字符计数器
valid++;
}
}
/** 判断是不是子串。
是子串则要更新长度,然后缩小窗口(用左指针遍历当前窗口)
*/
while (valid == tmap_size) { //有效字符数量与t相等
// 如果当前子串长度更小,则更新最小子串索引和长度
if (right - left+1 < minLen) {
start = left;
minLen = right - left+1;
}
/** 逐步缩小窗口,移除左指针的字符
*/
char d = s.charAt(left);
// 如果左指针元素是有效元素,则在smap中移除d字符
if (tmap.containsKey(d)) {
smap.put(d, smap.get(d) - 1);
// 移除字符 d 后,判断是否要更新有效字符数。比较smap与tmap中的d数量,如果d字符数量变少了,说明d是有效字符,所以移除d后,有效值需要减 1。
if(smap.get(d).intValue() < tmap.get(d).intValue() ){
valid--;
}
}
left++;
}
right++;
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(start, start + minLen); // 如果没有找到最小字符串则返回空字符串。否则返回 从索引start到索引start+minLen(不包含!!)
}
}
所有正文内容皆为本人原创,禁止搬运

浙公网安备 33010602011771号