题目来自编程之美
题目:与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 #