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 }
---恢复内容结束---