1222. 单词选择
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB
Description
我们都知道,学习英语单词最好的方法就是在相应的句子和语言环境中去学习它。小W最近定下了一个学习单词的计划,他有n个单词要背,但他想在通过背出一篇文章中的一段来记住这些单词。
假定现在小W手头有一篇包含m个单词的文章,现在他想在文章中找出连续的一段,其中包含最多的他所要背的单词(重复的只算一个),并且使这段连续的单词长度最短。这样他就可以用尽量短的时间学习到尽可能多的单词了。
Input
第一行一个数n(1<=n<=1000)
接下来n行每行是一个长度不超过10的字符串,表示一个要背的单词。
接着是一个数m(1<=m<=100000)
然后是m行长度不超过10的字符串,每个表示文章中的一个单词。
Output
两行,第一行为文章中最多包含的要背的单词数,第二行表示在文章中包含最多要背单词的最短的连续段的长度。
Sample Input
3hotdogmilk5hotdogdogmilkhot
Sample Output
33
不得不说,这题是一道经典的动态规划问题。找到文章中有多少单词是要背的单词这个问题很简单,下面解释怎么求解第二个问题。
当遇到一个单词的时候(规划尾指针):
1,这个单词是要背诵的单词,但是我们以前没有遇到,此时将这个单词的遇到的数量加一,并且更新我们的最小长度。
2,其他情况我们完全不必操作,因为只有遇到上述情况的单词才会对我们的结果产生影响。
每次尾指针规划完之后,我们都得规划头指针:
1,这个单词是我们不需要背诵的单词,那么直接丢弃这个单词,即将头指针指向下一个位置。
2,这个单词是要求背诵的单词,但是我们遇到过超过一次了,那么就将这次遇到的丢弃(头指针指向下一个位置)并且将这个单词我们遇到的数量减一。
卡了我很久,希望这样写出来能帮到后来人~
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <map>
using namespace std;
int main()
{
int n,m;
cin >> n;
string str;
map<string,bool> mp;
for(int i=0;i<n;i++)
{
cin >> str;
mp[str] = true;
}
cin >> m;
string word[100001];
map<string,int> f;
int mark1 = 0,mark2 = 0,l,cnt = 0;
while(mark2<m)
{
cin >> word[mark2];
if(mp[word[mark2]])
{
if(f[word[mark2]] == 0)
{
cnt++;
l = mark2-mark1+1;
}
f[word[mark2]]++;//这个单词出现的次数加一
}
while(mark1 < mark2)
{
//如果这个单词在first到last之间有多个,那么把first的这个删除
//把不需要的单词删除
if(mp[word[mark1]] == true && f[word[mark1]] >1 || mp[word[mark1]] == false)
{
f[word[mark1]]--;
mark1++;
}
else break;
}
if (mark2 - mark1 + 1 < l) l = mark2 - mark1 + 1;
mark2++;
}
cout << cnt << endl;
cout << l << endl;
return 0;
}