Solution 1
这道题根据名称和内容描述,基本可以判断是使用滑动窗口,也就是同向双指针进行最有区间的寻找(而非维护)。整体思路就是先移动右指针以扩展区间寻找能够满足要求的区间,然后再移动左指针以压缩空间,从而找到满足要求的最小区间。其中的「满足要求」的实现思路根据要求获得一个计数器,根据字符个数记录满足状态。这里我选择额外使用一个状态量保存当前满足要求的字符个数,省着每次都有遍历一遍计数器。
整体思路:
- 整理目标字符串,更新T计数器
- 在原始字符串上移动右指针,更新S计数器,并更新满足要求状态量
- 如果满足要求状态量不够,继续移动右指针
- 否则
- 移动左指针,更新S计数器,并更新满足要求状态量
- 如果状态量不够,跳出
- 否则,根据压缩的情况更新最优区间
- 时间复杂度: O ( m + n ) O(m + n) O(m+n),其中 m m m和 n n n分别为两个字符串的长度,因为需要进行一次线性遍历
- 空间复杂度: O ( m + n ) O(m + n) O(m+n),其中 m m m和 n n n分别为两个字符串的长度,需要创建两个计数器,最坏情况两个字符串所有字符都不相同
class Solution {
public:
string minWindow(string s, string t) {
unordered_map <char, int> counterS, counterT;
// 整理t中的字符情况
for (const auto &c: t) {
counterT[c]++;
}
// 所有需要满足的字符个数
int uniqueT = counterT.size();
int ansLen = -1, ansLeft = 0, ansRight = 0;
int leftP = 0, rightP = 0;
int uniqueS = 0; // 这里指满足T的字符个数
while (rightP < s.size()) {
// cout << "E " << leftP << " " << rightP << " " << s.substr(leftP, rightP - leftP + 1) << " " << ansLen << " " << ansLeft << " " << ansRight << endl;
// 剪枝:只考虑T中存在的字符
if (counterT.find(s[rightP]) != counterT.end()) {
counterS[s[rightP]]++;
if (counterS[s[rightP]] == counterT[s[rightP]]) {
// 满足要求
uniqueS++;
}
}
// 在满足要求时,左指针压缩(while里面直接作为触发判断了)
while (uniqueS == uniqueT && leftP <= rightP) {
// cout << "C " << leftP << " " << rightP << " " << s.substr(leftP, rightP - leftP + 1) << " " << ansLen << " " << ansLeft << " " << ansRight << endl;
if (ansLen == -1 || rightP - leftP + 1 < ansLen) {
ansLen = rightP - leftP + 1;
ansLeft = leftP;
ansRight = rightP;
}
// 左指针不断右移,直到不满足要求
if (counterT.find(s[leftP]) != counterT.end()) {
counterS[s[leftP]]--;
if (counterS[s[leftP]] < counterT[s[leftP]]) {
// 不再满足要求
uniqueS--;
}
}
leftP++;
}
rightP++;
}
return ansLen == -1? "": s.substr(ansLeft, ansRight - ansLeft + 1);
}
};
Solution 2
Solution 1的Python实现
class Solution:
def minWindow(self, s: str, t: str) -> str:
counterS, counterT = dict(), dict()
for c in t:
counterT[c] = counterT[c] + 1 if c in counterT else 1
uniqueT = len(counterT)
ansLen, ansLeft, ansRight = -1, 0, 0
leftP, rightP = 0, 0
uniqueS = 0
while rightP < len(s):
# print("E", leftP, rightP, s[leftP: rightP + 1], uniqueS, uniqueT, ansLen, ansLeft, ansRight)
if s[rightP] in counterT:
counterS[s[rightP]] = counterS[s[rightP]] + 1 if s[rightP] in counterS else 1
if counterS[s[rightP]] == counterT[s[rightP]]:
uniqueS += 1
while uniqueS == uniqueT and leftP <= rightP:
# print("C", leftP, rightP, s[leftP: rightP + 1], uniqueS, uniqueT, ansLen, ansLeft, ansRight)
if ansLen == -1 or rightP - leftP + 1 < ansLen:
ansLen = rightP - leftP + 1
ansLeft = leftP
ansRight = rightP
if s[leftP] in counterT:
counterS[s[leftP]] -= 1
if counterS[s[leftP]] < counterT[s[leftP]]:
uniqueS -= 1
leftP += 1
rightP += 1
return "" if ansLen == -1 else s[ansLeft: ansRight + 1]