题目来自编程之美
题目:与11年Alibaba笔试题一样。
已知:给定两个单词集合:一个是M个英文单词的集合,另一个是N个查询关键字的集合。每个英文单词以空格分隔,无其他标点符号;
求解:在英文单词集合中求解一个包含这N个查询关键字的最短子串。
注意:在这些求得的子串中,包含的查询关键字间的顺序可以与给出的查询关键字的顺序不同,只要包含所有关键字即可。
举例
给出的总的单词集合:w0 w1 w2 q0 w3 q1 w4 q1 w5 w6 w7q0 q1 w8
给出查询关键字的集合:q1 q0
在总的单词集合中,由好多包含所有关键字的区间,这里举几个例子:
<1>q0 w3 q1
<2>q0 w3 q1 w4 q1
<3>q0 w3 q1 w4 q1 w5 w6 w7 q0 q1
...等等
<4> q0 q1
其中最短的区间是q0 q1。
思路
举例
代码
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <assert.h>
using namespace std;
void Print(vector<string>& vArrStrContent,int nStart,int nEnd)
{
cout<<"区间: "<<nStart<<" - "<<nEnd<<endl;
cout<<"区间长度: "<<nEnd - nStart + 1<<endl;
for (int i = nStart;i <= nEnd;i++)
{
cout<<vArrStrContent[i]<<" ";
}
cout<<endl;
}
bool IsAllExisted(map<string,int>& mapQuery)
{
map<string,int>::iterator itCur = mapQuery.begin();
while(itCur != mapQuery.end() && itCur->second != 0)
{
itCur++;
}
if (itCur == mapQuery.end())
{
return true;
}
else
{
return false;
}
}
void FindShortestAbstract(vector<string>& vArrStrContent,vector<string>& vArrStrQuerys)
{
//遍历
int nCurStart = 0;
int nCurEnd = 0;
//保存最小信息
int nMinLen = 0x3f3f3f3f;
int nMinStart = 0;
int nMinEnd = 0;
//保存关键字所在位置
queue<int> qArrQueryPos;
int nLenContent = vArrStrContent.size();
int nLenQuery = vArrStrQuerys.size();
if (!nLenQuery || !nLenContent)
{
return;
}
//把所有关键字都放入哈希中
map<string,int> mapQuery;
for (int i = 0;i < nLenQuery;i++)
{
mapQuery[vArrStrQuerys[i]] = 0;
}
map<string,int>::iterator itCur;
int nLastQueryWords = 0;
while(nCurEnd < nLenContent)
{
/*队列为空,表示要寻找第一个包含关键字的区间,队列不为空,需要每次在队头删除一个关键字*/
if (!qArrQueryPos.empty())
{
nLastQueryWords = qArrQueryPos.front();
qArrQueryPos.pop();
mapQuery[vArrStrContent[nLastQueryWords]]--;
assert(mapQuery[vArrStrContent[nLastQueryWords]] > -1);
}
//寻找一个包含所有关键字的新区间
while(!IsAllExisted(mapQuery) && nCurEnd < nLenContent)
{
itCur = mapQuery.find(vArrStrContent[nCurEnd]);
if (itCur != mapQuery.end())//若条件成立,则表示nCurEnd指向的是关键字
{
itCur->second++;
qArrQueryPos.push(nCurEnd);
}
nCurEnd++;
}
if (IsAllExisted(mapQuery))//退出循环时,要么包含所有关键字,要么区间越界,遍历完毕。
{
//更新区间信息
int nTmpStart = qArrQueryPos.front();
int nTmpEnd = nCurEnd - 1;
if (nTmpEnd - nTmpStart + 1 < nMinLen)
{
nMinStart = nTmpStart;
nMinEnd = nTmpEnd;
nMinLen = nTmpEnd - nTmpStart + 1;
}
//输出测试信息
cout<<endl<<"本次区间: "<<endl;
Print(vArrStrContent,nTmpStart,nTmpEnd);
}
}
if (nMinLen != 0x3f3f3f3f)
{
cout<<endl<<"最小区间: "<<endl;
Print(vArrStrContent,nMinStart,nMinEnd);
cout<<endl;
}
else
{
cout<<"不包含所有关键字!"<<endl;
}
}
int main()
{
string str;
vector<string> vArrStrContent;
vector<string> vArrStrQuerys;
cout<<"输入内容: "<<endl;
while(cin>>str && str != "#")
{
vArrStrContent.push_back(str);
}
cout<<"输入查询关键字: "<<endl;
while(cin>>str && str != "#")
{
vArrStrQuerys.push_back(str);
}
FindShortestAbstract(vArrStrContent,vArrStrQuerys);
system("pause");
return 1;
}
//w0 w1 w2 q0 w3 q1 w4 q1 w5 w6 w7 q0 q1 w8 #
//q1 q0 #
//w0 w1 w2 q0 w3 q1 w4 q1 w5 w6 w7 q0 q1 #
//q1 q0 #