题目描述
知识点
滑动窗口
结果
实现
码前思考
- 这道题目是我学习“滑动窗口”的例题,所以我没有对这道题目进行过独立的思考,是按照别人的思路写的;
代码实现
//滑动窗口问题
//使用双指针进行解题
class Solution {
public:
string minWindow(string s, string t) {
//定义双指针,初始化都为最左边
int left = 0;
int right = 0;
//定义最小的长度,初始化为无限大
int len = INT_MAX;
//存储最小窗口开始的地方,这样start~start+len就是窗口的字符串了
int start = 0;
//两个hash,用于存储匹配需求和匹配实际
unordered_map<char,int> needs;
unordered_map<char,int> window;
//初始化needs
for(int i=0;i<t.size();i++){
needs[t[i]]++;
}
//表示匹配情况,初始为都没有匹配
int match = 0;
while(right < s.size()){ //只要还在范围之内
//如果当前字符是needs集合里面的字符
if(needs.count(s[right])){
window[s[right]]++;
//如果满足了匹配条件
if(window[s[right]] == needs[s[right]]){
match++;
}
}
//如果match达到了相应的数量
while(match == needs.size()){
//那么接下来就是记录长度并且滑动我们的left指针
if(right - left + 1 < len ){ //如果长度小于当前最短长度,那么要进行更新
len = right - left + 1;
start = left;
}
//开始进行右移,如果这个字符是needs里面需要的话
if(needs.count(s[left])){
window[s[left]]--;
if(window[s[left]] < needs[s[left]]){
match--;
}
}
left++;
}
right++;
}
string res = ((len == INT_MAX) ? "":s.substr(start,len));
return res;
}
};
上面代码写错了!!!!!!!!!!!!!!!!!错在下面:
if(needs.count(s[left])){
window[s[left]]--;
if(window[s[left]] < needs[s[left]]){
match--;
}
}
代码实现
//滑动窗口问题
//使用双指针进行解题
class Solution {
public:
string minWindow(string s, string t) {
//定义双指针,初始化都为最左边
int left = 0;
int right = 0;
//定义最小的长度,初始化为无限大
int len = INT_MAX;
//存储最小窗口开始的地方,这样start~start+len就是窗口的字符串了
int start = 0;
//两个hash,用于存储匹配需求和匹配实际
unordered_map<char,int> needs;
unordered_map<char,int> window;
//初始化needs
for(int i=0;i<t.size();i++){
needs[t[i]]++;
}
//表示匹配情况,初始为都没有匹配
int match = 0;
while(right < s.size()){ //只要还在范围之内
//如果当前字符是needs集合里面的字符
if(needs.count(s[right])){
window[s[right]]++;
//如果满足了匹配条件
if(window[s[right]] == needs[s[right]]){
match++;
}
}
//如果match达到了相应的数量
while(match == needs.size()){
//那么接下来就是记录长度并且滑动我们的left指针
if(right - left + 1 < len ){ //如果长度小于当前最短长度,那么要进行更新
len = right - left + 1;
start = left;
}
//开始进行右移,如果这个字符是needs里面需要的话
if(needs.count(s[left])){
if(window[s[left]] == needs[s[left]]){
match--;
}
window[s[left]]--;
}
left++;
}
right++;
}
string res = ((len == INT_MAX) ? "":s.substr(start,len));
return res;
}
};
码后反思
- 在这道题目里面,滑动窗口
[left,right]
表示的是以s[left]
为首的字符串,能够满足匹配字符串t
中的所有字符的最短字符串是[left,right]
。这个定义读起来很抽象,但是如果结合滑动窗口的过程理解就不难了; - 使用滑动窗口,我们始终要明确下面三个方面的知识:
right
右移是寻找可行解的过程;left
右移是寻找最优解的过程;- 理解滑动窗口
[left,right]
表达的含义是什么?
二刷代码
在二刷的时候,我对滑动窗口的理解就是以right为边界能够到达的最短匹配长度了。。。感觉有一点绕,我觉得还是之前的——“滑动窗口[left,right]
表示的是以s[left]
为首的字符串,能够满足匹配字符串t
中的所有字符的最短字符串是[left,right]
。” 更好理解一些。
我居然发现了两种理解滑动窗口的思路,真是神奇!
//滑动窗口问题,right移动代表寻找可行解集合,left代表寻找可行解集合中的最小解
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> mps;
unordered_map<char,int> mpt;
int lens = s.size();
int lent = t.size();
int match=0;
int curMatch=0;
int start;
int end;
int minSize=INT_MAX;
for(int i=0;i<lent;i++){
mpt[t[i]]++;
match++;//代表匹配的字符
}
int left = 0;
int right = 0;
while(right<=lens-1){
char rc = s[right];
if(mpt.count(rc)!=0){
if(mps[rc]<mpt[rc]){
curMatch++;
}
mps[rc]++;
}
//如果此时匹配的
if(curMatch==match){
//代表匹配,那么需要寻找最短的
while(true){
char lc = s[left];
if(mpt.count(lc)==0){
left++;
}else if(mpt.count(lc)!=0 && mps[lc]>mpt[lc]){
left++;
mps[lc]--;
}else{
break;//终止循环
}
}
if(right-left+1<minSize){
start=left;
end=right;
minSize=right-left+1;
}
}
right++;
}
if(minSize==INT_MAX){
return "";
}else{
return s.substr(start,minSize);
}
}
};