原题链接
示例
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
思路
设立左指针left和右指针right
右指针向右移动
循环移动右指针
本质上,就是遍历每一个s[right]结尾的,没有重复字符的最长子串,从中找到最长的。
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int left = 0, right = 0, res = 0;
unordered_map<char, int>window;
while(right < s.size()){
char c1 = s[right++];
// s[left, right)
window[c1]++;
while(window[c1] > 1){
char c2 = s[left];
window[c2]--;
left++;
}
res = max(res, right - left);
}
return res;
}
};
题目链接
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
思路
原字符串s使用窗口[left, right),不断移动右指针,每当满足包含子串,就开始移动左指针,缩小窗口,一旦左指针移动到不满足包含子串,继续移动右指针,找下一个符合条件的窗口。
问题一:如何判断窗口是否包含子串
class Solution {
public:
string minWindow(string s, string t) {
int left = 0, right = 0;
unordered_map<char, int> need;
unordered_map<char, int>window;
for(char c: t)need[c]++;
int valid = 0, start = 0, len = INT_MAX;
while(right < s.size()){
char c1= s[right++];
if(need.count(c1)){
window[c1]++;
if(window[c1] == need[c1])
valid++;
}
while(valid == need.size()){
if(len > right - left){
len = right - left;
start = left;
}
char c2 = s[left++];
if(need.count(c2)){
if(window[c2] == need[c2])valid--;
window[c2]--;
}
}
}
return len == INT_MAX? "":s.substr(start, len);
}
};
题目链接
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例
输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
思路
和上一题的框架相同,只需要实现包含子串而且不包含其他的串。
如果valid == need而且 window == s1.size() 即为条件。
代码
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char, int>need, window;
int left = 0, right = 0, valid = 0;
for(char c : s1) need[c]++;
while(right < s2.size()){
char c1 = s2[right++];
if(need.count(c1)){
window[c1]++;
if(window[c1] == need[c1])valid++;
}
while(valid == need.size()){
//改变就在这里,实现包含子串而且只有子串没有其他元素
if(right - left == s1.size())return true;
char c2 = s2[left++];
if(need.count(c2)){
if(need[c2] == window[c2])valid--;
window[c2]--;
}
}
}
return false;
}
};
题目链接
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序
示例
输入:
s: "cbaebabacd" p: "abc"
输出:
[0, 6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的字母异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的字母异位词。
代码
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> need, window;
vector<int> res;
int left = 0, right = 0, valid = 0;
for(char c: p) need[c]++;
while(right < s.size()){
char c1 = s[right++];
if(need.count(c1)){
window[c1]++;
if(window[c1] == need[c1]){
valid++;
}
}
while(valid == need.size()){
if(right - left == p.size()) res.push_back(left);
char c2 = s[left++];
if(need.count(c2)){
if(window[c2] == need[c2])valid--;
window[c2]--;
}
}
}
return res;
}
};