Alibaba笔试题:根据关键字求最短摘要字串

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

  解:简化题目:从一个字符串A中找出包含另一个字符串B所有字母的最小字串。(比A短,并每个字母只出现一次;这里先排除了关键词多次出现的情况,这种情况只需稍微改动即可),考虑使用两个指针p、q指向A起始位置,遍历指针p,

1、使得q到p之间包含了B中的所有字母。这时可以是使用一个数组来记录p中走过A中遇到B中字母出现的次数。这样当所有字母全非0的时候,即可。这时未能保证q到p是以*p结尾子句中包含所有字母的最短的一个。

2、此时走动q指针,另q走到恰好q到p是以*p结尾子句中包含所有字母的最短的一个。

如A=dccdaadc B=cda

经过第一步,q指向A[0],p指向A[4] 计数数组 221 字串dccda并不是以A[4]结尾子句中最短的包含B的子串

然后,走q指针。走过A[1]时,计数数组121,即此时还是包含了B(ccda),所有继续再走;直到A[2]时,计数数组为111,下一个将出现不能包含B的全部字母所以此时A[2]~A[4]为以A[4]结尾子句中包含所有字母的最短的一个。

3、然后记录相应信息。q走过一个,使得q~p未能包含全部的B,这时又回到了第一步,直至整个字符串检测完毕。

这里的代码并未考虑关键字出现多次的情况。这种情况只需要稍做改动即可;

  1 #include <iostream>
  2 
  3 using namespace std;
  4 
  5 
  6 //p指向的单词(空格结尾或'\0'),在关键词组中是否存在,存在则相应计数;当所有关键字计数
  7 //不为0,即包含了所有的关键字了,以*flag回传1
  8 //返回单词的后一个位置(若为'\0'则返回'\0')
  9 char* countkw_add(int cnt[], char *p, char * kw[], int n, int *falg)  //
 10 {
 11     char *q;
 12     char tmp[50]={0};
 13     q = tmp;
 14     while(*p && *p!=' ')*q++ = *p++;
 15 
 16     *q = '\0';
 17     
 18     for (int i=0; i<n; i++)
 19     {
 20         if (strcmp(tmp, kw[i])==0)
 21         {
 22             cnt[i]++;
 23             for(int j=0; j<n; ++j)
 24             {
 25                 if (!cnt[j])
 26                 {
 27                     break;
 28                 }
 29             }
 30             if (j==n)
 31             {
 32                 *falg  = 1;  //包含了所有的关键字
 33             }
 34             break; //找到
 35         }
 36     }
 37     while(*p && *p++!=' '); //
 38 
 39     return p;
 40 }
 41 //由于只有计数数组cnt的数据全非零时才调用此函数
 42 //p指向的单词(空格结尾或'\0'),在关键词组中是否存在,存在则减去相应计数;当存在关键字计数
 43 //不为0,即未包含所有的关键字了,以*flag回传0
 44 //返回单词的后一个位置(若为'\0'则返回'\0')
 45 char* countkw_sub(int cnt[], char *p, char * kw[], int n, int *falg)
 46 {
 47     char *q;
 48     char tmp[50]={0};
 49     q = tmp;
 50     while(*p && *p!=' ')*q++ = *p++;
 51     
 52     *q = '\0';
 53     
 54     for (int i=0; i<n; i++)
 55     {
 56 
 57         if (strcmp(tmp, kw[i])==0)
 58         {
 59             cnt[i]--;
 60             
 61             if (cnt[i]==0)
 62             {
 63                 *falg  = 0;  //缺关键字kw[i]
 64             }
 65             break; //找到
 66         }
 67     }
 68     while(*p && *p++!=' '); //
 69 
 70     return p;
 71 }
 72 
 73 void extractSummery(char *des, char * keywords[], int n, char **beg, char **end)
 74 {
 75     char *p,*q;
 76 
 77     int  *cnt;
 78     int minlen=strlen(des); //
 79     *beg = NULL;
 80     *end = NULL;
 81 
 82     cnt = (int *)malloc(sizeof(int)*n);
 83     memset(cnt, 0, sizeof(int)*n);
 84 
 85     
 86     q= des;
 87     while(*q!='\0' && *q==' ')q++;
 88 
 89     p = q;
 90     int fulled=0;
 91 
 92     while(*p!='\0')
 93     {
 94         
 95         p = countkw_add(cnt,p,keywords,n, &fulled);
 96 
 97         while(*p && *p==' ')p++;
 98 
 99         if (fulled) //包含了所有的关键字
100         {
101             char *tmp;
102             tmp = q;
103             while(fulled)
104             {
105                 q = tmp; //记录上一次
106                 tmp= countkw_sub(cnt,tmp,keywords,n, &fulled);
107             }
108 
109             if (p-q<minlen) //发现更小的,则更新
110             {
111                 minlen = p-q;
112                 *beg = q;
113                 *end = p;
114             }
115             //while(*q && *q!=' ')q++; 
116             q = tmp;
117             while(*q && *q==' ')q++; //指向下一个词
118         }
119             
120     
121 
122     }
123 }
124 
125 
126 
127 
128 int main()
129 {
130     char des[] = "aefo aec egne a se a fe a aec ve  fjfj as lel";
131 
132     char *kw[] = {"aec" ,"a", "fjfj"};
133     char *b,*e;
134 
135     extractSummery(des,kw,3,&b,&e);
136 
137     for(char *p=b; p<e; p++)
138     {
139         cout<<*p;
140     }
141 
142     cout<<endl;
143 
144     return 0;
145 }

 

---恢复内容结束---

posted @ 2013-03-17 21:54  legendmaner  阅读(600)  评论(0编辑  收藏  举报