转自 http://blog.csdn.net/bertzhang/article/details/7278728
题目:抽象点说,就是在一个字符串中,找一些目标字符串,找到包含所有目标字符串的最小字符串。题目虽然叫做最短摘要生成,但和实际的搜索snippet的计算还是有比较大的差距的。
解法:文献[1]给出了一种比较好的解法,策略还是使用双指针,双指针对于很多算法设计很有价值,算法的思想是采用两个指针,开始两个指针都指向缓冲区的头部,尾指针向后扫描,直到头指针和尾指针中间包含了全部的关键字,那么头指针向后移动,直到包含全部关键字这个条件失败,这时截取字串并和已取得的最小字串比较,如果小则替换。头指针、尾指针都向后一个位置(这点很重要,开始就忘记了移动头指针,导致程序出错),继续扫描。另外,由于一个关键字可能重复多次,因此在判断是否包含全部关键字时要采用计数机制,才能保证查看的准确。这样只要头指针和尾指针扫描两次字符串就可以完成生成算法。
#include <stdio.h>
#include <string>
#include <map>
class KeyWordChecker {
public:
KeyWordChecker() : current_state_(false) {}
void AddKeyWord(const std::string& word) {
if (keywords_.find(word) == keywords_.end()) {
keywords_[word] = 0;
}
}
bool IsContainAllKeyWord(const std::string& word, bool add) {
if (keywords_.find(word) == keywords_.end()) {
return current_state_;
}
if (add) {
keywords_[word]++;
} else {
keywords_[word]--;
}
std::map<std::string, int>::iterator begin = keywords_.begin();
int counter = 0;
while (begin != keywords_.end()) {
if (begin->second > 0) {
counter++;
} else {
break;
}
begin++;
}
if (counter == keywords_.size()) {
current_state_ = true;
return true;
} else {
current_state_ = false;
return false;
}
}
private:
std::map<std::string, int> keywords_;
bool current_state_;
};
std::string GenerateSnippet(const std::string& content, KeyWordChecker* keyword_checker) {
int begin = 0;
int end = 0;
std::string snippet;
int min_length = content.size();
while (end < content.size()) {
if (!keyword_checker->IsContainAllKeyWord(std::string(1, content[end]), true)) {
end++;
continue;
}
while (begin <= end && keyword_checker->IsContainAllKeyWord(std::string(1, content[begin]), false)) {
begin++;
}
if (end - begin + 1 < min_length) {
snippet = content.substr(begin, end - begin + 1);
min_length = end - begin + 1;
}
end++;
begin++;
}
return snippet;
}
int main(int argc, char** argv) {
std::string content = "abbbbbcaaadebmmmmdcfg";
KeyWordChecker keyword_checker;
keyword_checker.AddKeyWord("b");
keyword_checker.AddKeyWord("d");
std::string snippet = GenerateSnippet(content, &keyword_checker);
printf("snippet:%s\n", snippet.c_str());
}
另外一个代码转自 http://hi.baidu.com/leifenglian/item/33fc082a88c49cd0a517b6d3
// MinAbstractGenerate.cpp : 定义控制台应用程序的入口点。
//
/*
最短摘要生成:
有一个字符串数组序列W,一个关键词数组Q,
在W中找出包含所有关键词组Q中元素的最短序列
*/
/*吐血的算法。。。*/
#include "stdafx.h"
#include <iostream>
using namespace std;
//是否包含所有的字符串
bool isAllExisted(char * src[],int start,int end,char *des[],int deslen)
{
for(int j=0;j<deslen;j++)
{
bool isFind=false;
for(int i=start;i<end;i++)
{
if(strstr(src[i],des[j])!=NULL)
{
isFind=true;
}
}
if(isFind==false)
{
return false;
}
}
return true;
}
//最小摘要生成
void minAbstractGenerate(char * src[],int srclen,char *des[],int deslen)
{
int min=0;
int max=0;
int begin=0;
int end=0;
int distance=srclen;
while(true)
{
while(!isAllExisted(src,min,max,des,deslen) && min<=max)
{
max++;
}
while(isAllExisted(src,min,max,des,deslen))
{
if(max-min<distance)
{
distance=max-min;
begin=min;
end=max;
}
min++;
}
if(max>=srclen-1)
{
break;
}
}
while(begin<end)
{
cout<<src[begin++]<<"***";
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char *src[]={"ab","ef","cd","gh","ij","k","c","ef","t","ij","yz"};
char *dec[]={"ef","ij"};
minAbstractGenerate(src,11,dec,2);
return 0;
}
转自 http://www.cnblogs.com/jack204/archive/2012/09/03/2668667.html
题目:
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
分析
当初看这道题时,看了好了几遍都没看懂。后来总算弄明白:给出的字符串是用其它程序分好词的,关键字符串也是用其它程序分好词的,而不是按用户直接输入的字符串。比如书上给的例子:“微软亚洲研究院 使命”,不是按空格分成两个关键词,“微软亚洲研究院”和“使命”,而是按其它程序分成:“微软”、“亚洲”、“研究院”和“使命”四个关键词。
“最短摘要”应该是指:包含所有关键字(关键字不要求按用户输入的顺序排列)的长度最短的摘要。书上的解法,把“最短摘要”理解成包含所有关键字且词个数最少的摘要。
这个过程要记录最短文摘的信息。
这个时间复杂度是 O(N ^ 2 * M)
N 是文档的长度
M 是关键词数组的大小
总结的滑动窗口法是:
------------------------------------------------------
使用滑动窗口的办法,找出最短摘要。我们把这个滑动窗口叫做摘要滑动窗口。
摘要滑动窗口左边界L,右边界R。
窗口中应该维护的信息:
- 窗口中已经遍历过的关键字序列----可使用队列才存储;
- 窗口中各个关键字出现的个数----可使用hashtable来表示或者数组也行。
[while]
右边界R向右移动的原则:
当前窗口中不包含所有种类的关键字,R向右移动寻找更新的关键字。
左边界L向右移动的原则:
当前窗口中已经包含了所有种类的关键字,计算当前摘要长度,并从队列中拿出一个关键字,即L向右移动一个关键字;
L与R一直移动下去,一直到R不能往右移动时候,循环结束。
[end while]