算法分析与设计 练习三

算法分析与设计 练习三 内容
分别用KMP、Monte Carlo和Las Vegas算法编写,随机生成10000对、长度较长、且长度不等的01文本串X()和模式Y()(三个程序处理相同的串)
假设文本串长度为size1,模式串长度为size2
1.
【算法分析与设计 练习三】思路:
(1).KMP的主要思想
当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了 。
(2).next数组 == 前缀表( table)
1)前缀表记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀 。
2)前缀表是用来回退的,它记录了模式串与文本串不匹配的时候,模式串应该从哪里开始重新匹配 。
3)下标5(包括5)之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa。因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面从新匹配就可以了 。
(3).构造next数组
其实就是计算模式串s,前缀表的过程 。
1)初始化
2)处理前后缀不相同的情况:向前回溯
3)处理前后缀相同的情况
2.
Monte Carlo算法:
总能得到问题的一个解,但不一定是正确解 。然而可以通过多次运行原算法,并且满足每次运行时的随机选择都相互独立,这样就使产生非正确解的概率减到任意小 。
思路:
通过对字符串“取指纹”判断字符串是否相等
取指纹的方法:
由于文本串和模式串是由0-1组成,将文本串和模式串由二进制转换为十进制 。选取一个质数P,对文本串和模式串的十进制编码与P做取模运算 。若取模结果相同,则视为二者匹配 。
文本串取指纹的优化方法:
由于在文本串中相邻的子串的“取指纹”值满足下面的关系:
getFp(X(i + 1)) = (2 * getFp(X(i)) - 2 ^ size2 * X[i] + X[i + size2]) % P,
其中getFp为取指纹函数,X(i)表示文本串中以X[i]为开头,长度为size2的子串

算法分析与设计 练习三

文章插图
3.
Las Vegas算法:
不断调用随机算法求解,直到求得正确解或调用次数达到某个阈值 。所以,不一定能得到解,如果能得到解,一定是正确解 。
思路:
在Monte Carlo算法的基础上进行优化:
当两字符串的取指纹结果相等时,则进行逐一比对,若比对结果相同,则二者匹配;若比对结果不同,则继续向后进行模式匹配 。
4.源码
#include #include #include #include #include #include using namespace std;//构造next数组void getNext(vector& next, const string& needle){//初始化int j = -1;next[0] = j;for(int i = 1;i < needle.size();++i){//前后缀不相同的情况:向前回溯while (j >= 0 && needle[i] != needle[j + 1]){j = next[j];}//前后缀相同的情况if(needle[i] == needle[j + 1]){++j;}next[i] = j;}}//KMP算法,从文本串haystack中找到模式串needle第一次出现的位置int subStringKMP(string haystack, string needle){if (needle.size() == 0) return 0;if (haystack.size() == 0) return -1;if (haystack.size() < needle.size()) return -1;int size1 = haystack.size();int size2 = needle.size();vector next(size2);getNext(next, needle);int j = -1;for(int i = 0;i < size1;++i){while(j >= 0 && haystack[i] != needle[j + 1]){j=next[j];}if(haystack[i] == needle[j + 1]){++j;}if (j == size2 - 1){return i - size2 + 1;}}return -1;}//大素数const int mod = 1e9 + 7;//辅助函数, 将二进制转换为十进制long long binaryToDecimal(string s){int size = s.size();long long sum = 0;for (int i = 0;i < size;++i){if (s[i] == '1'){sum = sum + pow(2, size - 1 - i);}}return sum;}//辅助函数,取指纹int getFingerprint(long long decimal){return decimal % mod;}//Monte Carlo算法,从文本串haystack中找到模式串needle第一次出现的位置int subStringMC(string haystack, string needle){int size1 = haystack.size();int size2 = needle.size();if (size2 == 0) return 0;long long needleDecimal = binaryToDecimal(needle);long long haystackDecimal = binaryToDecimal(haystack.substr(0, size2));int needleFingerprint = getFingerprint(needleDecimal);int haystackFingerprint = getFingerprint(haystackDecimal);for (int i = 0;i