《编程之美》——最短摘要的生成
来源:互联网 发布:机械迷城mac中文版 编辑:程序博客网 时间:2024/05/01 07:35
问题:
(简化)输入两个字符串,一个表示用户输入的搜索关键词,另一个表示一篇网页的内容。对于搜索关键词和网页分别进行自动分词后,用户输入的搜索关键词和网页内容的两个字符串变为两个词语序列。所求摘要即为网页序列中包含搜索关键词序列的最短的子串。
(网页序列包含搜索关键词序列里面的所有词语,但是不要求顺序相同,最短摘要是网页字符串中所有满足这样要求的最短子串。)
分析与解法:
假设W数组是经过网页分词之后的结果,其中W[0], W[1],…, W[n]为一些已经分好的词语;Q数组是用户输入的搜索关键词,其中Q[0], Q[1],…, Q[m]为所有输入的搜索关键词。
w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1
【解法一】
- 从W数组的第一个位置开始查找出一段包含所有关键词数组Q的序列,计算当前的最短长度,并更新结果序列;
- 对目标数组W进行遍历,从第二个位置开始,重新查找包含所有关键词数组Q的序列,同样计算出其最短长度,以及更新包含所有关键词的结果序列,然后求出最短距离;
- 依次操作下去,一直到遍历至目标数组W的最后一个位置为止。
时间复杂度是O(m*n^2)。
【解法二】
第一种解法中有大量的重复计算,对其进行优化。第一次扫描的时候,假设需要包含所有的关键词,从第一个位置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的序列,并且找出其中的最小值,就可得到最终的结果。
时间复杂度是O(m+n)。
书中代码如下,
int nTargetLen = N + 1; // 设置目标长度为总长度+1 int pBegin = 0; // 初始指针 int pEnd = 0; // 结束指针 int nLen = N; // 目标数组的长度为N int nAbstractBegin = 0; // 目标摘要的起始地址 int nAbstractEnd = 0; // 目标摘要的结束地址 while(true) { // 假设未包含所有的关键词,并且后面的指针没有越界,往后移动指针 while(!isAllExisted() && pEnd < nLen) { pEnd++; } // 假设找到一段包含所有关键词信息的字符串 while(isAllExisted()) { if(pEnd – pBegin < nTargetLen) { nTargetLen = pEnd – pBegin; nAbstractBegin = pBegin; nAbstractEnd = pEnd – 1; } pBegin++; } if(pEnd >= N) Break; }
全部代码实现如下,
#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://blog.csdn.net/bertzhang/article/details/7278728
- 编程之美——最短摘要的生成
- 《编程之美》——最短摘要的生成
- 编程之美 最短摘要生成
- 编程之美之最短摘要生成的困惑
- 编程之美--最短摘要的生成
- 编程之美读书笔记--3.5 最短摘要的生成
- 编程之美--3.5最短摘要的生成
- 编程之美--最短摘要的生成
- 最短摘要的生成(编程之美)
- 编程之美-3.5最短摘要的生成
- 编程之美----3.5最短摘要的生成
- 编程之美-最短摘要的生成方法整理
- 编程之美读书笔记-最短摘要的生成
- 编程之美之最短摘要生成
- 编程之美--3.5最短摘要生成
- 编程之美--3.5最短摘要生成
- 读书笔记之编程之美 - 3.5 最短摘要的生成
- 编程之美: 第三章 结构之法 3.5最短摘要的生成
- 深入浅出MIPS 三 MIPS的协处理器CP0 (Section 2)
- java定时器 schedule和scheduleAtFixedRate区别
- Ajax访问后台500 (Internal Server Error)问题
- JavaScript边学边记
- IntelliJ IDEA 安装scala开发插件
- 《编程之美》——最短摘要的生成
- html5屏幕旋转事件,html5如何实现屏幕旋转
- ios9适配
- eclipse按住ctrl点布局文件只能跳转到R文件
- Mysql优化
- 我对管理和领导的理解
- 自定义AVPlayer
- 深入浅出MIPS 三 MIPS的协处理器CP0 (Section 3)
- Gradle