#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>using namespace std;
/*
问题:有个内含单词的超大文本文件,给定任意两个单词,找出在这个文件中这两个单词的最短距离(也即相隔几个单词)。有办法在O(1)时间里完成搜索操作吗?解法的空间复杂度如何?
分析:这个是编程之美的最短摘要算法。简单的例子:假设寻找的是: "m" "a",假设文本为: c d a a b e m m r a e g g m关键就是要确保搜索中一直能够移动下标,设字符串数组为A,遍历当前字符串数组,如果寻找到两个单词中其中一个,记录其下标为i,如果后续继续找到某个单词记录其下标j如果A[i] = A[j],说明两个单词相同,则令j=-1,否则,说明两个单词不相同,记录单词距离d=|j-i|,如果d < 最小单词距离minDis,更新minDis=d,minIndex1=i,minIndex2=j不断移动两个单词的下标,记录最短距离和最短距离单词所在位置
输入:
m a(n个待搜索的单词)
14(文本中单词个数)
c d a a b e m m r a e g g m
输出:
2(最短距离)
m r a(最短摘要,从搜索的单词1开始到搜索的单词2结尾)关键:
1 书上解法:最简单的是遍历字符串列表,找到每个单词出现的下标,将属于同一个单词的下标集合以数组形式存放,然后将两个数组排序,选取出自不同数组的连续差值最小的作为结果即可比如: 对于单词数组  : c d a a b e m m r a e g g m单词m 出现的下标集合:{6,7,13}单词a               :{2,3,9}标记数组:{2a,3a,6b,7b,9a,13b}
2    设字符串数组为A,遍历当前字符串数组,如果寻找到两个单词中其中一个,记录其下标为i,如果后续继续找到某个单词记录其下标j如果A[i] = A[j],说明两个单词相同,则令j=-1,否则,说明两个单词不相同,记录单词距离d=|j-i|,如果d < 最小单词距离minDis,更新minDis=d,minIndex1=i,minIndex2=j不断移动两个单词的下标,记录最短距离和最短距离单词所在位
3 此题与之前的编程之美:最短摘要生成不同的是,最短摘要生成是通过:首先设置起始,截止指针begIndex,endIndex,遍历字符串找到一组下标begIndex,endIndex,使得能够包含所有待查找字符串;没有找到最短摘要,就endIndex++;找到最短摘要,就begIndex++;       即让某个被查找的元素不再包含到最短摘要中,这样来促使endIndex继续移动发生变化*/typedef struct Result
{Result(){}Result(int index1 , int index2 , int mDis , string& sResult):_index1(index1),_index2(index2),_minDis(mDis),_searchResult(sResult){}int _index1;//单词1的起始位置int _index2;//单词2的起始位置int _minDis;string _searchResult;
}Result;enum ArrayFlag{ARRAY1 , ARRAY2};typedef struct Value
{Value(int value, ArrayFlag flag):_value(value),_arrayFlag(flag){}int _value;ArrayFlag _arrayFlag;bool operator < (const Value& other) const{return _value < other._value;}
}Value;Result search2(vector<string>& words , string& word1 , string& word2)
{Result invalidResult(-1, -1 , -1, string(""));if(words.empty() || word1.empty() || word2.empty() || word1 == word2){return invalidResult;}vector<Value> indexs;int size = words.size();for(int i = 0 ; i < size ; i++){//每当找到一个单词时,就进行比较if( words.at(i) == word1 ){indexs.push_back(Value( i , ARRAY1));}else if( words.at(i) == word2 ){indexs.push_back(Value( i , ARRAY2));}}sort(indexs.begin() , indexs.end());//排好序遍历相邻两个来自不同数组的元素int length = indexs.size();int minDis = INT_MAX;Result result;for(int i = 1 ; i < length ; i++){//两个不同的数组if(indexs.at(i-1)._arrayFlag != indexs.at(i)._arrayFlag){int dis = abs( indexs.at(i-1)._value - indexs.at(i)._value);if(dis < minDis){minDis = dis;result._minDis = minDis;result._index1 = indexs.at(i-1)._value;result._index2 = indexs.at(i)._value;}}}//如果单词1在前面int beginIndex = result._index1 < result._index2 ? result._index1 : result._index2;int endIndex = result._index1 > result._index2 ? result._index1 : result._index2;stringstream stream;for(int i = beginIndex ; i <= endIndex ; i++){stream << words.at(i) << " ";}result._searchResult = stream.str();return result;
}Result search(vector<string>& words , string& word1 , string& word2)
{Result invalidResult(-1, -1 , -1, string(""));if(words.empty() || word1.empty() || word2.empty() || word1 == word2){return invalidResult;}int pos1 = -1 , pos2 = -1;int size = words.size();int minDis = INT_MAX;Result result;bool isFind = false;for(int i = 0 ; i < size ; i++){//每当找到一个单词时,就进行比较if( words.at(i) == word1 ){pos1 = i;isFind = true;}else if( words.at(i) == word2 ){pos2 = i;isFind = true;}//如果找到了某个单词,开始进行比较if(!isFind){continue;}//如果另一个单词已经确定位置了if(pos2 >= 0 && pos1 >= 0){int dis = abs(pos1 - pos2);if(dis < minDis){minDis = dis;result._minDis = minDis;result._index1 = pos1;result._index2 = pos2;}//是否更新当前pos为新找到的pos:如果发现产生了最短距离就更新;否则说明找到的pos位置很远,如果更新,会导致后续的搜索结果都比较差;//一定要更新新找到的位置,因为最好的结果已经保存了,即使更新后会使得后续结果变差,但不影响}isFind = false;}//如果单词1在前面int beginIndex = result._index1 < result._index2 ? result._index1 : result._index2;int endIndex = result._index1 > result._index2 ? result._index1 : result._index2;stringstream stream;for(int i = beginIndex ; i <= endIndex ; i++){stream << words.at(i) << " ";}result._searchResult = stream.str();return result;
}void process()
{int searchWordNum;vector<string> words;//这里假设读取的文章是一个大的字符串string text;string searchWord;string word1 , word2;while(cin >> word1 >> word2){words.clear();cin >> searchWordNum;for(int i = 0 ; i < searchWordNum ; i++){cin >> searchWord;words.push_back(searchWord);}//Result result = search(words , word1, word2);Result result = search2(words , word1, word2);cout << result._minDis << endl << result._searchResult << endl;}
}int main(int argc , char* argv[])
{process();getchar();return 0;
}

程序员面试金典——解题总结: 9.18高难度题 18.5有个内含单词的超大文本文件,给定任意两个单词,找出在这个文件中这两个单词的最短距离相关推荐

  1. 程序员面试金典——解题总结: 9.17中等难题 17.9设计一个方法,找出任意指定单词在一本书中的出现频率

    #include <iostream> #include <stdio.h> #include <vector> #include <string.h> ...

  2. 程序员面试金典——解题总结: 9.17中等难题 17.7给定一个整数,打印该整数的英文描述(例如 One Thousand,Two Hundred-Thirty Four)

    #include <iostream> #include <stdio.h> #include <string> #include <vector> # ...

  3. C#LeetCode刷题-程序员面试金典

    本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:C#LeetCode刷题-程序员面试金典 | .Net中文网. C#LEETCODE刷题概述 概述 所有LeetCode程序员面试金典 ...

  4. 回文链表 牛客网 程序员面试金典 C++ Python

    回文链表 牛客网 程序员面试金典  C++ Python 题目描述 请编写一个函数,检查链表是否为回文. 给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文. 测试样例 ...

  5. 程序员面试金典 - 面试题 17.11. 单词距离(multimap平衡二叉搜索树)

    1. 题目 有个内含单词的超大文本文件,给定任意两个单词,找出在这个文件中这两个单词的最短距离(相隔单词数). 如果寻找过程在这个文件中会重复多次,而每次寻找的单词不同,你能对此优化吗? 示例: 输入 ...

  6. 《程序员面试金典》解题目录(更新完毕)

    题目来源于LeetCode上的<程序员面试金典>,这里做一个目录方便大家查找.另外有本人的LeetCode解题目录.<剑指Offer>解题目录.LintCode代码能力测试CA ...

  7. 程序员面试金典——18.13 最大字母矩阵

    程序员面试金典--18.13 最大字母矩阵 在牛客网上把此题的难度给大大降低了......... Solution1: 参考网址:https://www.nowcoder.com/questionTe ...

  8. 程序员面试金典——18.12最大和子矩阵

    程序员面试金典--18.12最大和子矩阵 Solution1: 参考网址: [1]https://www.cnblogs.com/GodA/p/5237061.html 思想讲的很清楚~ [2]htt ...

  9. 【To Do】程序员面试金典——18.11最大子方阵

    程序员面试金典--18.11最大子方阵 Solution1:我的答案.最笨的方法,时间复杂度是O(n3)O(n3)O(n^3) class SubMatrix { public:int maxSubM ...

最新文章

  1. php把数组组成xml,php 怎么将数组转xml的函数?
  2. SA-SSD:阿里达摩院最新3D检测力作(CVPR2020)
  3. 《Linux From Scratch》第三部分:构建LFS系统 第八章:让LFS系统可引导 - 8.2. 创建 /etc/fstab 文件...
  4. 用php生成html文件,怎样用PHP生成html文件
  5. 性感的CSS Menus
  6. TCP/IP总结(4)TCP 概述
  7. 对注册表项的访问被拒绝的解决
  8. 域名解析IP服务器地址
  9. imessage_重新设计iMessage以获得更好的用户体验— UX案例研究
  10. LAMP架构,纯文本作品
  11. 马云刘强东隔空互怼,美团外卖大范围故障,苹果系统漏洞百出 | 一周业界事
  12. [Ubuntu] apache .htaccess根据访问的域名指向不同的目录
  13. python遍历文件夹下所有文件
  14. 利用Python生成钢琴音色
  15. 告别动态规划,连刷40道动规算法题,我总结了动规的套路
  16. 线性代数学习笔记(二)——n阶行列式
  17. 我是不是该安静的走开
  18. C基础 工程中常用的排序
  19. 一辈子不用考试?你可能是个假程序员
  20. mysql错误+126_MySQL,错误126:表的密钥文件不正确

热门文章

  1. git报错:error: failed to push some refs to ... 的解决办法及如何让线上覆盖本地方法【Git/SVN】
  2. (29)Verilog实现倍频【方法二】
  3. 使用ProxySelector选择代理服务器
  4. 2014新浪校招笔试题:取水果(17年第一篇让人懵逼的面试题)
  5. 为什么要用vue,他解决了什么问题,如何使用它?
  6. php程序员就业方向,php程序员发展方向_php程序员有前途吗
  7. c语言int转换成float,int怎么转化为float 将 int型变量n转换成float型变量的方法是...
  8. 高效清除电脑中的灰尘。。。。社会工程学真的很管用
  9. UEFI开发探索94 – 迷宫小游戏
  10. oracle10显示数据库错误,Oracle10gR2数据库出现ORA-3136错误的解决方法