转自http://s.sousb.com/2011/04/15/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E-%E6%9C%80%E7%9F%AD%E6%91%98%E8%A6%81/

Alibaba笔试题:给定一段产品的英文描述,包含M个英文字母,每个英文单词以空格分隔,无其他标点符号;再给定N个英文单词关键字,请说明思路并编程实现方法String extractSummary(String description,String[] key words),目标是找出此产品描述中包含N个关键字(每个关键词至少出现一次)的长度最短的子串,作为产品简介输出。(不限编程语言)20分。

  这道笔试题和编程之美最短摘要生成的方法类似,先来看看这些序列:

w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

     问题在于,如何一次把所有的关键词都扫描到,并且不遗漏。扫描肯定是无法避免的,但是如何把两次扫描的结果联系起来呢?这是一个值得考虑的问题。

     沿用前面的扫描方法,再来看看。第一次扫描的时候,假设需要包含所有的关键词,从第一个位置w0处将扫描到w6处:

w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

     那么,下次扫描应该怎么办呢?先把第一个被扫描的位置挪到q0处。

w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

     然后把第一个被扫描的位置继续往后面移动一格,这样包含的序列中将减少了关键词q0。那么,我们便可以把第二个扫描位置往后移,这样就可以找到下一个包含所有关键词的序列。即从w4扫描到w9处,便包含了q1,q0:

w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

     这样,问题就和第一次扫描时碰到的情况一样了。依次扫描下去,在w中找出所有包含q的序列,并且找出其中的最小值,就可得到最终的结果。

 

  1. #include "stdafx.h"  
  2. #include "iostream"  
  3. #include <vector>  
  4. #include <string>  
  5. #include<set>  
  6. #include <map>  
  7. using namespace std;  
  8.  
  9. void FindMinLenAbstract()    
  10. {    
  11.     int n;  //number of document words    
  12.     int m;  //number of keywords    
  13.  
  14.     while (cin>>n>>m) {    
  15.  
  16.         // input    
  17.         vector<string> seq;    
  18.         while (n--)    
  19.             *back_inserter(seq) = *istream_iterator<string>(cin);    
  20.  
  21.         set<string> kwords;    
  22.         while (m--)    
  23.             *inserter(kwords, kwords.end()) = *istream_iterator<string>(cin);    
  24.  
  25.         // find shortest abstract    
  26.         typedef vector<string>::iterator Vsit;    
  27.  
  28.         //q is current scan range, and r is min abstract range    
  29.         pair<Vsit, Vsit> q(seq.begin(), seq.begin()), r(seq.begin(),seq.end());    
  30.  
  31.         //record words that not being found between q.first and q.second    
  32.         set<string> notfound = kwords;    
  33.  
  34.         //record words with an associate appearance count    
  35.         //that being found between q.first and q.second    
  36.         map<string, int> found;    
  37.  
  38.         for(;;) {    
  39.  
  40.             //still have keyword not being found    
  41.             if (!notfound.empty()) {    
  42.  
  43.                 //all conditions have being considered    
  44.                 if (q.second == seq.end())    
  45.                     break;    
  46.  
  47.                 set<string>::iterator it = notfound.find(*q.second);    
  48.  
  49.                 //current word is an not-found word    
  50.                 if (it != notfound.end()) {    
  51.                     ++found[*it];    
  52.                     notfound.erase(it);    
  53.                 }    
  54.                 else {    
  55.                     map<string, int>::iterator it2 = found.find(*q.second);    
  56.                     if (it2 != found.end())    
  57.                         ++(it2->second);    
  58.                 }    
  59.  
  60.                 //next keyword in sequence    
  61.                 ++(q.second);    
  62.             }    
  63.  
  64.             //all keywords have being found    
  65.             else {    
  66.  
  67.                 // find an min range from q.first to q.second that    
  68.                 // include all keywords.    
  69.                 map<string, int>::iterator it = found.find(*q.first);    
  70.                 if (it != found.end() && !--(it->second)) {    
  71.                     size_t rlen = distance(r.first, r.second);    
  72.                     size_t qlen = distance(q.first, q.second);    
  73.                     if (!rlen || rlen > qlen) r = q;    
  74.  
  75.                     notfound.insert(it->first);    
  76.                     found.erase(it);    
  77.                 }    
  78.  
  79.                 ++(q.first);    
  80.             }    
  81.         }    
  82.  
  83.         // output    
  84.         if (r.second == seq.end() && r.first == seq.begin())    
  85.             cout<<"No abstract available.";    
  86.         else {    
  87.             if (r.first != seq.begin())    
  88.                 cout<<"... ";    
  89.             for (bool first = true; r.first != r.second; ++r.first, first = false) {    
  90.                 if (!first)    
  91.                     cout<<' ';    
  92.                 cout<<*r.first;    
  93.             }    
  94.             if (r.second != seq.end())    
  95.                 cout<<" ...";    
  96.         }    
  97.         cout<<'\n';    
  98.     }    
  99. }    
  100.  
  101. int main(int argc, char* argv[])  
  102. {  
  103.     FindMinLenAbstract();    
  104.     return 0;  
  105. }