0%

C++|滑动窗口专题

最近在整理之前刷过的leetcode题目,想写写一些常见的、典型的解题技巧或者方法。最开始刷题的时候,总觉得题目好难,其实刷多了题,也就那么回事😆。这篇博客主要想介绍一下滑动窗口方法(sliding window),对于解决字符串问题非常有用🤩~

这一篇解答写的非常的透彻,详细请参看链接:滑动窗口思想

滑动窗口,主要是用来解决子串问题。一般的解决思路是:首先,我们定义left与right两个标志,用来界定滑动窗口的左右边界;接着,我们不断地移动右边界,即right++;当满足某一条件之后,我们不断地移动左边界,即left++,缩减滑动窗口的大小,直到满足最后的条件,然后返回结果。下面以leetcode上的三道题为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
3.无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
*/


#include<stdio.h>
#include<string.h>
#include<string>
#include<vector>
#include<unordered_set>
#include<iostream>
#include<unordered_map>
using namespace std;

class Solution {
public:
/*
滑动窗口的思想。
*/
int lengthOfLongestSubstring(string s) {
if(s.size()==0) return 0;

int left=0,right=0;
unordered_map<char,int> m;
int maxsize=0;

while(right<s.size()){
char c1=s[right];
m[c1]++;
right++;

while(m[c1]>1){
char c2=s[left];
m[c2]--;
left++;
}

maxsize=max(maxsize,right-left);

}

return maxsize;
}
};

int main(){
string s;
cin>>s;
Solution so1;
int ans=so1.lengthOfLongestSubstring(s);
printf("%d\n",ans);
return 0;



}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/*
76. 最小覆盖子串

给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。

示例:

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"

*/

#include<stdio.h>
#include<string.h>
#include<string>
#include<vector>
#include<unordered_map>
#include<algorithm>
#include<iostream>
using namespace std;

class Solution{
public:
/*
滑动窗口思想。碰到字串问题,第一时间就应该想到滑动窗口。
*/
string minWindow(string s, string t) {
if(t.size()==0 || s.size()==0) return "";

unordered_map<char,int> m_t;
unordered_map<char,int> window;
for(int i=0;i<t.size();i++) m_t[t[i]]++;

int left=0,right=0;//双指针,滑动窗口的左右位置
int start=0,minlen=INT_MAX;//start表示最后的字符串的开始的位置,minlen表示最后的字符串的长度
int match=0;//窗口内与目标字符串匹配的数目

//移动right
while(right<s.size()){
char c1=s[right];
if(m_t.count(c1)){
window[c1]++;
if(window[c1]==m_t[c1]){
match++;
}
}
right++;

//如果已经匹配了,说明窗口内的字符串包含了目标字符串,接下来,就需要缩减窗口大小,移动left,找到包含目标字符串的最小子串
while(match==m_t.size()){
char c2=s[left];
if(right-left<minlen){
start=left;
minlen=right-left;
}
if(m_t.count(c2)){
window[c2]--;
if(window[c2]<m_t[c2]){
match--;
}
}
left++;
}
}

return minlen==INT_MAX?"":s.substr(start,minlen);
}
};

int main(){
string s,t;
cin>>s>>t;

Solution so1;
string ans=so1.minWindow(s,t);
cout<<ans<<endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
438. 找到字符串中所有字母异位词

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。

字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。

说明:

字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。
示例 1:

输入:
s: "cbaebabacd" p: "abc"

输出:
[0, 6]

解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。

*/

#include<stdio.h>
#include<string.h>
#include<string>
#include<vector>
#include<algorithm>
#include<iostream>
#include <set>
#include<unordered_map>
using namespace std;

class Solution{
public:
/*
滑动窗口思想。https://leetcode-cn.com/problems/minimum-window-substring/solution/hua-dong-chuang-kou-suan-fa-tong-yong-si-xiang-by-/
*/
vector<int> findAnagrams(string s, string p) {
vector<int> ans;
if(s.size()==0) return ans;

unordered_map<char,int> m_p;
unordered_map<char,int> window;
int left=0,right=0;

int match=0;

for(int i=0;i<p.size();i++) m_p[p[i]]++;

while(right<s.size()){
char c1=s[right];
if(m_p.count(c1)){
window[c1]++;
if(window[c1]==m_p[c1]){
match++;
}
}
right++;

while(match==m_p.size()){
char c2=s[left];
if(right-left==p.size()){
ans.push_back(left);
}
if(m_p.count(c2)){
window[c2]--;
if(window[c2]<m_p[c2]){
match--;
}
}
left++;
}
}

return ans;
}
};

int main(){
string s,p;
cin>>s>>p;
Solution so1;

vector<int> ans=so1.findAnagrams(s,p);
for(int i=0;i<ans.size();i++){
printf("%d ",ans[i]);
}
printf("\n");
return 0;
}

具体代码应该很清楚啦,over☕️~

Would you like to buy me a cup of coffee☕️~