双指针的子序列匹配问题,老样子,对于双指针问题,应该先写出暴力怎么做
class Solution {
public:
string findLongestWord(string s, vector<string>& dictionary) {
sort(dictionary.begin(),dictionary.end(),[](const auto &a,const auto &b)
{
if(a.size()!=b.size())
return a.size()<b.size();
else
for(int i=0;i<a.size();i++)
if(a[i]!=b[i])
return a[i]>b[i];
return false;
});
for(int k=dictionary.size()-1;k>=0;k--)
{
string aim=dictionary[k];
for(int i=0;i<s.size();i++)
{
int l=0,valid=0;
if(aim[l]!=s[i]) continue;
for(int j=i;j<s.size();j++)
{
if(aim[l]==s[j]) valid++,l++;
if(valid==aim.size()) return aim;
}
}
}
return "";
}
};
虽然暴力可以ac,但是还是用双指针优化一下
其实我们发现,我们的第二重第三重循环,只需要保留一个循环就可以了
暴力:先找到一个左端点,固定左端点,然后延伸右端点直到满足或者尾部
换一个左端点,右端点会清零
双指针优化:先找到一个左端点,固定左端点,延伸右端点直到满足或者维护
换一个右端点,右端点不会清零
int valid=0,l=0;
for(int i=0,j=0;i<s.size();)
{
if(j<i) j=i;
if(s[i]!=aim[0])
{
i++;
continue;
}
while(j<s.size()&&valid<aim.size())
{
if(aim[l]==s[j]) valid++,l++;
j++;
}
if(valid==aim.size()) return aim;
i++;
}
其实这样子的双指针也是使用了双指针---维护区间信息的特性(即滑动窗口),我们其实可以不用维护一个窗口,直接从0开始枚举到尾部,查看有没有存在这个字典就行了(因为题目要求的是是否存在,而不是要求窗口最小)
于是进一步优化如下
string findLongestWord(string s, vector<string>& dictionary) {
sort(dictionary.begin(),dictionary.end(),[](const auto &a,const auto &b)
{
if(a.size()!=b.size())
return a.size()<b.size();
else
for(int i=0;i<a.size();i++)
if(a[i]!=b[i])
return a[i]>b[i];
return false;
});
for(int k=dictionary.size()-1;k>=0;k--)
{
string aim=dictionary[k];
int valid=0,l=0;
for(int i=0;i<s.size();)
{
if(aim[l]==s[i]) l++,valid++;
if(valid==aim.size()) return aim;
i++;
}
}
return "";
}