最近在读《编程之美》,学习的过程中难免情不自禁的想coding一下,验证一下。
书上关于“最短摘要的生成”问题给出了两种解决办法。算法一实在是没什么技术含量,就不多说了。算法二中通过改变查找的起始地址减少了查找的次数,有效的降低了算法的时间复杂度。书中关于这部分的描述可以参见http://www.cnblogs.com/flyoung2008/archive/2012/04/08/2437489.html
从书中的代码参考可知:
isAllExisted()算法是在w[pBegin]-w[pEnd]区间对摘要q[]进行查找的。
pEnd起始为0,然后自增,因为pEnd一开始较小,可能小于q数组的长度,所以isAllExisted()必然返回false。如果去除pEnd的限制就可以减少isAllExisted()调用次数。
下面是我用C++实现的算法:
#include <iostream>
#include <string.h>
using namespace std;
char w[][15]= //words数组
{
"we",
"are",
"chinese",
"we",
"love",
"china",
"because",
"china",
"is",
"our",
"motherland",
"and",
"we",
"live",
"there",
"too"
};
char k[][15]= //摘要单词数组
{
"we",
"love",
"china"
};
//返回1说明找到所有摘要单词,返回0表示失败
//参数s,e为引用,用于返回找到的摘要位置,s表示最靠前的摘要单词下标,e表示最后一个摘要单词下标
//wlen为words数组长度,klen为keys数组长度
int find_summary(char w[][15],char k[][15],int wlen,int klen,int low,int &s,int &e)
{
int i,j;
e=low;
s=wlen-1;
for(i=0;i<klen;i++)
{
for(j=low;j<wlen;j++)
{
if(0==strcmp(k[i],w[j]))
{
s=j<s? j:s;
e=j>e? j:e;
break; //找到当前的摘要单词,继续查找下一个摘要单词
}
}
if(j>=wlen) //找不到当前的摘要单词,查找失败
return 0;
}
return 1; //找到所有的摘要单词,查找成功
}
int main()
{
int wlen=sizeof(w)/sizeof(w[0]);
int klen=sizeof(k)/sizeof(k[0]);
cout<<"Words:"<<endl<<"\t";
for(int i=0;i<wlen;i++)
cout<<w[i]<<" ";
cout<<endl;
cout<<"Kyes:"<<endl<<"\t";
for(i=0;i<klen;i++)
cout<<k[i]<<" ";
cout<<endl;
cout<<"find:"<<endl;
int targetLen = wlen+1; //用于保存最短摘要长度
int targetStart = -1; //用于保存最短摘要起始位置
int targetEnd = -1; //用于保存最短摘要结束位置
int s,e;
int low=0;
while(find_summary(w,k,wlen,klen,low,s,e)) //从low位置开始查找摘要
{
cout<<"\t";
for(i=s;i<=e;i++)
cout<<w[i]<<" ";
cout<<endl;
if(e-s+1<targetLen)
{
targetLen = e-s+1;
targetStart = s;
targetEnd = e;
}
low = s+1; //下一次查找的起始位置为s+1
}
cout<<"Best:"<<endl;
cout<<"\tLength: "<<targetLen<<"\tStart: "<<targetStart<<"\tEnd:"<<targetEnd<<endl;
return 0;
}
输出结果: