方法一:每次都得遍历滑动窗口、模式串的哈希表,来判断是否覆盖
class Solution {
public:
int charToIndex(char c){ //大写字母的索引在前,小写字母的索引在后
if(c>='A' && c<='Z'){
return c-65;
}else if(c>='a' && c<='z'){
return c-71;
}
return -1;
}
bool ifMatch(vector<int> sM, vector<int> tM){
for(int i=0;i<sM.size() && i<tM.size();i++){
if(sM[i]<tM[i]){
return false;
}
}
return true; //若为true,则主串覆盖了模式串
//这就是导致时间复杂度变成O(n*m)的罪魁祸首!!
//每次判断滑动窗口是否覆盖模式串,都得遍历一次两者的哈希表!
}
string minWindow(string s, string t) {
string result="";
int sLength=s.length();
int tLength=t.length();
if(sLength<tLength){
return result;
}
vector<int> strIndex(2,0); //存储子串下标
int L=0; //子串长度初始化为0
//主串滑动窗口的哈希表、模式串的哈希表初始化
int left=0; //主串左边界
int right=tLength-1; //主串右边界
vector<int> sM(52,0),tM(52,0); //主串s、模式串t的哈希表
for(int i=0;i<tLength;i++){ //哈希表均初始化
sM[charToIndex(s[i])]++;
tM[charToIndex(t[i])]++;
}
while(right<sLength){
if(ifMatch(sM,tM)){ //成功覆盖,则做记录,左边界收缩
if(L==0 || L>(right-left+1)){
strIndex[0]=left;
strIndex[1]=right;
L=right-left+1;
}
sM[charToIndex(s[left])]--;
left++;
}else{
if(right+1<sLength){
sM[charToIndex(s[++right])]++;
}else{
break;
}
}
}
if(L==0){
return result;
}else{
return s.substr(strIndex[0],strIndex[1]-strIndex[0]+1);
}
}
};
如果是每次都是模式串的哈希表中的元素与滑动窗口中对应的元素比较大小,时间效率就变成了O(n*m)了!
方法二:只比较右边界和左边界的元素在两者哈希表中的value值!
class Solution {
public:
int charToIndex(char c){ //字符到下标的哈希函数
if(c>='A' && c<='Z'){ //大写字母下标从0到25
return c-65;
}
else if(c>='a' && c<='z'){ //小写字母下标从26到51
return c-71;
}else{
return -1;
}
}
string minWindow(string s, string t) {
string result="";
int sLength=s.length();
int tLength=t.length();
if(sLength<tLength){
return result;
}
vector<int> sHash(52,0),tHash(52,0);
//滑动窗口与模式串的哈希表,key值为所包含的字符对应的下标,value为字符出现的频率
//使用vector容器代替unordered_map容器
//数组下标索引还是比计算哈希函数快,所以时间效率变快了!
for(int i=0;i<tLength;i++){
tHash[charToIndex(t[i])]++; //模式串哈希表初始化
}
for(int right=0,left=0,count=0;right<sLength;right++){
//滑动窗口左右边界、覆盖字符数初始化为0
sHash[charToIndex(s[right])]++; //将右边界字符放入滑动窗口的哈希表中
if(sHash[charToIndex(s[right])]<=tHash[charToIndex(s[right])]){
count++;
//右边界字符频率小于等于模式串中的,则表明滑动窗口覆盖了一个字符
}
while(left<right && sHash[charToIndex(s[left])]>tHash[charToIndex(s[left])]){
//若滑动窗口中左边界的字符超过了模式串t中对应字符的数量时(也有可能是模式串中没有这个字符!)
//模式串中没有的字符、有但是多余的字符都要舍弃!所以,令左边界收缩!
sHash[charToIndex(s[left++])]--;
}
//所以能保证count只增不减!!!
if(count==tLength){
//此时,完全覆盖住了模式串,判断是否更新最小子串的长度
if(result.length()==0 || result.length()>right-left+1){
result=s.substr(left,right-left+1);
}
}
}
return result;
}
};
由于是控制右边界和左边界元素对应在滑动窗口和模式串哈希表中的value关系,时间效率是O(n+m),快了不少!
不知道leetcode438也能借鉴这个方法不?虽然那道题直接把哈希表一把判断相等时间效率也很高了……