30. 串联所有单词的子串
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例 1:
输入:
s = "barfoothefoobarman",
words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 “barfoo” 和 “foobar” 。
输出的顺序不重要, [9,0] 也是有效答案。
示例 2:
输入:
s = "wordgoodgoodgoodbestword",
words = ["word","good","best","word"]
输出:[]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题
哈希储存word中每一个string;
滑动窗口对s中每一个words总长度的字符串进行遍历,计数后与存储words的哈希表进行比较,若完全相同,即可;
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
int len=words.size();
vector<int> res;
if(!len) return res;
int n=words[0].size();
int wide= n*len; //总长度
if(s.size()<wide) return res;
//字典存放每个词使用的次数
unordered_map<string,int> dic;
for(string t:words) dic[t]++;
string tmp; //扫描每一个子串
unordered_map<string,int> T;
bool flag;
for(int i=0;i<s.size()-wide+1;i++)
{
flag=false;
tmp=s.substr(i,wide); //截取这段字符串
//对tmp里每一个n比较
int f=0;
while(f<wide){
string tt=tmp.substr(f,n);
//看tt是否在dic中,若在则新建map里+1;
//若不在,则continue
if(dic.count(tt)) T[tt]++;
else {
flag=true;
break;
}
f+=n;
}
for(auto i=T.begin();i!=T.end();i++)
{
if(i->second!=dic[i->first]) {
flag=true;
break;
}
}
if(!flag) res.push_back(i);
T.clear(); //清空map
}
return res;
}
};
注意点
哈希表间可以==比较,if(T==dic) res.push_back(i);
。
清空哈希表:T.clear()
。
76. 最小覆盖子串
解法1:暴力二重循环
class Solution {
public:
string minWindow(string s, string t) {
int len=t.size();
if(!len) return "";
//哈希表储存t里每个字母的次数
unordered_map<char,int> dic;
for(char a:t) dic[a]++;
int n=s.size();
if(n<len) return "";
string tmp;
int MINLEN=INT_MAX;
int start=-1;
int end=0;
unordered_map<char,int> T;
for(int i=0;i<n-len+1;i++)
for(int j=i+len;j<=n;j++)
{
tmp=s.substr(i,j-i);
for(char t:tmp)
if(dic.count(t)) T[t]++;
bool flag=1;
for(auto t=dic.begin();t!=dic.end();t++)
if((t->second)>T[t->first]){
flag=0;
break;
}
if(flag&&(j-i)<MINLEN)
{
MINLEN=j-i;
start=i;
end=j-1;
}
T.clear();
}
string res="";
if(start!=-1) res=s.substr(start,end-start+1);
return res;
}
};
解法2:滑动窗口+map判断改进
map存储t里每一个字符个数,遍历s,当s[i]在map中时(–map[s[i]]>=0)且cnt++,当cnt==t时说明整个数组匹配成功,记录此时的start与end,并与max比较;
然后右移left,若map[left++]>0说明该left在匹配的范围内,cnt–;
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> map;
for (auto c : t) map[c]++;
int left = 0, cnt = 0, maxlen = s.size() + 1, start = left;
for (int i = 0; i < s.size(); ++i) {
if (--map[s[i]] >= 0) ++cnt;
while(cnt == t.size()) {
if (maxlen > i - left + 1) {
maxlen = i - left + 1;
start = left;
}
if (++map[s[left]] > 0) cnt--;
left++;
}
}
return maxlen == s.size() + 1 ? "" : s.substr(start, maxlen);
}
};