百度2005年的笔试题
1.实现 void delete_char(char * str, char ch);
把str中所有的ch删掉
2.把字符串S中所有A子串换成B
3.搜索引擎的日志要记录所有查询串,有一千万条查询,不重复的不超过三百万
要统计最热门的10条查询串. 内存<1G. 字符串长 0-255
(1) 主要解决思路 //具体用词和原题不大一样
(2) 算法及其复杂度分析
4.有字典,设计一个英文拼写纠正算法 (1) 思想 (2) 算法及复杂度 (3) 改进
5. { aaa, bb, ccc, dd }, { bbb, ff }, { gg } 等一些字符串的集合
要求把交集不为空的集合并起来,如上例会得到 { aaa, bb, ccc, dd, ff }, {gg}
(1) 思想 (2) 算法及复杂度 (3) 改进
1.实现 void delete_char(char * str, char ch);
把str中所有的ch删掉
- #include <iostream>
- #include <stack>
- using namespace std;
- void delete_char(char *str, char ch)
- {
- int i,j;
- i = j = 0;
- while(str[i])
- {
- if(str[i] != ch)
- {
- str[j++] = str[i++];
- }else
- i++;
- }
- str[j] = '\0';
- }
- int main()
- {
- char str[]= "abccbaccab";
- delete_char(str, 'c');
- cout << str << endl;
- }
#include <iostream>
#include <stack>
using namespace std;
void delete_char(char *str, char ch)
{
int i,j;
i = j = 0;
while(str[i])
{
if(str[i] != ch)
{
str[j++] = str[i++];
}else
i++;
}
str[j] = '\0';
}
int main()
{
char str[]= "abccbaccab";
delete_char(str, 'c');
cout << str << endl;
}
2.把字符串S中所有A子串换成B
- 转自:http://www.baidu.com/s?wd=%B0%D1%D7%D6%B7%FB%B4%AES%D6%D0%CB%F9%D3%D0A%D7%D3%B4%AE%BB%BB%B3%C9B
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- int get_next(char* t,int next[])
- {
- int i = 0;
- int k = -1;
- int len = strlen(t);
- next[0] = k;
- while(i<len-1)
- {
- if( k==-1 || t[i]==t[k] )
- {
- k++;
- i++;
- if(t[i] != t[k])
- next[i] = k;
- else
- next[i] = next[k];
- }
- else
- k = next[k];
- }
- }
- int kmp_find(char* s,char* t)
- {
- int i = 0;
- int j = 0;
- int len1 = strlen(s);
- int len2 = strlen(t);
- int next[len2];
- get_next(t,next);
- while(i<len1 && j<len2)
- {
- if( j==-1 || s[i] == t[j])
- {
- i++;
- j++;
- }
- else
- j = next[j];
- }
- if(j>=len2)
- return i-len2;
- else
- return -1;
- }
- char* substr(char* s,char* a,char* b)
- {
- int len = strlen(a);
- int index = kmp_find(s,a);
- //kmp find where is a in s or you can use strstr
- char* head = s;
- *(head+index) = '\0';
- char* tail = s + index + len;
- //把字符串s分为 head a tail三部分
- sprintf(s,"%s%s%s",head,b,tail);
- if(kmp_find(s,a) != -1)//如果替换一个后还含有a继续
- return substr(s, a, b);
- else
- return s;
- }
- int main(int argc, char *argv[])
- {
- char* s = (char*)malloc(100);
- memset(s,0,100);
- sprintf(s,"%s",argv[1]);
- printf("str:%s\n",s);
- printf("sub:%s by %s\nafter:%s\n",argv[2],argv[3],substr(s, argv[2], argv[3]));
- free(s);
- s=NULL;
- system("PAUSE");
- return 0;
- }
- 赠送shell实现
- echo "xxxxxx" | sed 's/xxx/xxx/g'
- awk -v str="sadsadas" 'BEGIN{gsub(/xxx/,"xxxxx",str);print str}'
- vi ed等edit内直接s/xx/xxx/g
- 玩笑的呵呵...
转自:http://www.baidu.com/s?wd=%B0%D1%D7%D6%B7%FB%B4%AES%D6%D0%CB%F9%D3%D0A%D7%D3%B4%AE%BB%BB%B3%C9B
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_next(char* t,int next[])
{
int i = 0;
int k = -1;
int len = strlen(t);
next[0] = k;
while(i<len-1)
{
if( k==-1 || t[i]==t[k] )
{
k++;
i++;
if(t[i] != t[k])
next[i] = k;
else
next[i] = next[k];
}
else
k = next[k];
}
}
int kmp_find(char* s,char* t)
{
int i = 0;
int j = 0;
int len1 = strlen(s);
int len2 = strlen(t);
int next[len2];
get_next(t,next);
while(i<len1 && j<len2)
{
if( j==-1 || s[i] == t[j])
{
i++;
j++;
}
else
j = next[j];
}
if(j>=len2)
return i-len2;
else
return -1;
}
char* substr(char* s,char* a,char* b)
{
int len = strlen(a);
int index = kmp_find(s,a);
//kmp find where is a in s or you can use strstr
char* head = s;
*(head+index) = '\0';
char* tail = s + index + len;
//把字符串s分为 head a tail三部分
sprintf(s,"%s%s%s",head,b,tail);
if(kmp_find(s,a) != -1)//如果替换一个后还含有a继续
return substr(s, a, b);
else
return s;
}
int main(int argc, char *argv[])
{
char* s = (char*)malloc(100);
memset(s,0,100);
sprintf(s,"%s",argv[1]);
printf("str:%s\n",s);
printf("sub:%s by %s\nafter:%s\n",argv[2],argv[3],substr(s, argv[2], argv[3]));
free(s);
s=NULL;
system("PAUSE");
return 0;
}
赠送shell实现
echo "xxxxxx" | sed 's/xxx/xxx/g'
awk -v str="sadsadas" 'BEGIN{gsub(/xxx/,"xxxxx",str);print str}'
vi ed等edit内直接s/xx/xxx/g
玩笑的呵呵...
3.搜索引擎的日志要记录所有查询串,有一千万条查询,不重复的不超过三百万
要统计最热门的10条查询串. 内存<1G. 字符串长 0-255
(1) 主要解决思路 //具体用词和原题不大一样
(2) 算法及其复杂度分析
- //未完待续
- //基本思路:
- #include <iostream>
- #include <fstream>
- #include <map>
- #include <string>
- using namespace std;
- string* topTen()
- {
- ifstream fin("test.txt");
- if(!fin)
- {
- exit(0);
- }
- map<string, int> m;
- string s;
- while(fin >> s)
- {
- m[s] ++;
- }
- string heap[10];
- int c = 0;
- for(map<string,int>::iterator it = m.begin(); it!= m.end();it++)
- {
- if(c < 10)
- }
- }
- int main()
- {
- }
//未完待续
//基本思路:
#include <iostream>
#include <fstream>
#include <map>
#include <string>
using namespace std;
string* topTen()
{
ifstream fin("test.txt");
if(!fin)
{
exit(0);
}
map<string, int> m;
string s;
while(fin >> s)
{
m[s] ++;
}
string heap[10];
int c = 0;
for(map<string,int>::iterator it = m.begin(); it!= m.end();it++)
{
if(c < 10)
}
}
int main()
{
}
4.有字典,设计一个英文拼写纠正算法 (1) 思想 (2) 算法及复杂度 (3) 改进
- 转自:http://9.douban.com/site/entry/24428719/
- 本文想从Office中的Word的语法检查和纠正功能发散开来,探讨一下这方面的相关算法和对问题的思考方式,以及怎么样从其他类似的地方受到启发不断解决新的问题。
- 先简单说说问题吧,我们在使用Word的时候经常会发现有些单词比如school,一不小心给敲成了shcool或者shool,这个时候Word会很体 贴地提示我们这个英语单词错了(很简单shcool,shool在Word的字典库中都没有出现过,所以肯定错了),接下来Word给出了好几个单词都长 得特别像shcool,让我们最快地修正错误,今天真正要讲的就是Word怎么判断两个字符串的相似程度(长的像)的(相似程度越高就越要给你推荐纠正)
- 下面涉及的算法有Spelling suggestion(拼写纠正算法)、Spell checker(拼写检查算法)、Bloom Filter(布隆过滤器)、longest common substring(最大公共子串),Levenshtein distance(我不知道怎么恰当的翻译,大概意思是计算一个字符串变到另一个字符串所需要的步骤吧,也就是两个字符串的相似程度,步骤越短当然越相似)
- 第一步Word肯定要能判断这个单词正确与否的,自然最合适的是使用布隆过滤器了(Bloom Filter), 其实布隆过滤器的原理很简单:通过Hash将所有正确的单词都记下来,然后再来了一个字符串的话,对它进行Hash,然后检查Hash出来的地址上有没有 记号,没有的话表示这个字符串在我们的正确单词库中没有任何单词能够和他匹配,那肯定就错了,这就是布隆过滤器的思想,但是你一想的话发现在我们的这个需 求中不需要在Hash表中存储正确单词的内容了(所以不需要能装下整个词典那么大的空间了),最简单用一个Bit表示(0表示没有,1表示有)这个位置上 有没有正确的单词就可以了,这样就节省了大量空间!毕竟这个需求比我们传统的使用Hash的时候要简单,所以没有理由为Key付出代价:),具体还可以参 考Google的吴军的数学之美系列文章,这样就达到了一个字符串是否为一个正确的单词了,不是的话就要接下来找一个最有可能的单词来推荐我们修正他。(到这里就完成了拼写检查的功能,当然Bloom Filter还有很多其他用处)
- 接下来在讲述如何判断两个字符窜的相似程度的时候我们先来看看另外一个问题(下面的内容是摘录自http://www.5do8.com/blog/doc/569/index.aspx):LCS(longest common substring)算法,即最大公共子串,它是求两个字符串最长公共子串的问题(就是两个字符串中最长的公共部分)。大体解法是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0。然后求出对角线(确切来说是矩阵斜线)最长的1序列,其对应的位置就是最长匹配子串的位置.
- 例如,有两个字符串:
- A= I MISS MY CODE HI
- B= One Like MY Code
- 这里,先忽略掉大小写,通吃,在C#或者PHP中,String.ToLower()或者lower()可以考虑.对于其中的特殊字符,例如空格,可以在比较的时候直接删除.另外,该算法比较与顺序无关,可以随意的翻转字符串.接下来比较.
- i m i s s m y c o d e h i
- o 0 0 0 0 0 0 0 0 1 0 0 0 0
- n 0 0 0 0 0 0 0 0 0 0 0 0 0
- e 0 0 0 0 0 0 0 0 0 0 1 0 0
- l 0 0 0 0 0 0 0 0 0 0 0 0 0
- i 1 0 1 0 0 0 0 0 0 0 0 0 1
- k 0 0 0 0 0 0 0 0 0 0 0 0 0
- e 0 0 0 0 0 0 0 0 0 0 1 0 0
- m 0 1 0 0 0 1 0 0 0 0 0 0 0
- y 0 0 0 0 0 0 1 0 0 0 0 0 0
- c 0 0 0 0 0 0 0 1 0 0 0 0 0
- o 0 0 0 0 0 0 0 0 1 0 0 0 0
- d 0 0 0 0 0 0 0 0 0 1 0 0 0
- e 0 0 0 0 0 0 0 0 0 0 1 0 0
- 在上面的矩阵图中,其中的红色(最长的1串)就可以看成匹配的字符串. (摘录完毕)
- 或者这样标示矩阵会更方便:
- i m i s s m y c o d e h i
- o 0 0 0 0 0 0 0 0 1 0 0 0 0
- n 0 0 0 0 0 0 0 0 0 0 0 0 0
- e 0 0 0 0 0 0 0 0 0 0 1 0 0
- l 0 0 0 0 0 0 0 0 0 0 0 0 0
- i 1 0 1 0 0 0 0 0 0 0 0 0 1
- k 0 0 0 0 0 0 0 0 0 0 0 0 0
- e 0 0 0 0 0 0 0 0 0 0 1 0 0
- m 0 1 0 0 0 1 0 0 0 0 0 0 0
- y 0 0 0 0 0 0 2 0 0 0 0 0 0
- c 0 0 0 0 0 0 0 3 0 0 0 0 0
- o 0 0 0 0 0 0 0 0 4 0 0 0 0
- d 0 0 0 0 0 0 0 0 0 5 0 0 0
- e 0 0 0 0 0 0 0 0 0 0 6 0 0
- 最大数字是6,所以最长公共子串的长度是6,开始位置可以从6所在的位置推算出来(i-6,j-6)就可以了
- 好了这个问题到这里是完美优美地解决了,非常好理解,我当时反正感觉非常是受震撼(其实我每次看到好算法都是这样的)然后就琢磨了这个算法背后的原理、思 想是什么它还能应用在哪些方面,正好我以前做个一个算法这么样计算两个字符串的匹配程度(当时是用匹配度不断加权计算出来的相似度,并进行了一些特殊处理 才马马虎虎对特殊情况非常合适,呵呵太弱了吧),感觉这两个问题特别相似,既然这个矩阵记录了所有的匹配情况,那么我可以这样想所有斜线(平行对角线)上 的数字加起来平方,这样得到一个数字,越大的话应该是两个字符串在不同的地方匹配整体匹配度越高(画图实在不方便,我不知道大家理解我的意思了没有,呵 呵,当时我是这样想的)。因为虽然LCS算法解决的只是最长公共子串的问题,但是这个算法还帮我们得到了所有其他地方匹配的公共子串(不是最长的那些,当 然也要在相似度中纳入计算的),所以我觉得这个想法是在LCS原理上的一个拓展,同样是成立的。
- 接下来我们再来看看拼写纠正的时候先进行的相似度判断:Levenshtein distance (下面的例子和伪代码摘自Wiki:Levenshtein distance,非常简单我就偷懒了,要我画出这个图形简直是太不可能了,好麻烦的):
- A commonly-used bottom-up dynamic programming algorithm for computing the Levenshtein distance involves the use of an (n + 1) × (m + 1) matrix, where n and m are the lengths of the two strings. This algorithm is based on the Wagner-Fischer algorithm for edit distance. Here is pseudocode for a function LevenshteinDistance that takes two strings, s of length m, and t of length n, and computes the Levenshtein distance between them:
- int LevenshteinDistance(char s[1..m], char t[1..n])
- // d is a table with m+1 rows and n+1 columns
- declare int d[0..m, 0..n]
- for i from 0 to m
- d[i, 0] := i
- for j from 1 to n
- d[0, j] := j
- for i from 1 to m
- for j from 1 to n
- if s[i] = t[j] then cost := 0
- else cost := 1
- d[i, j] := minimum(
- d[i-1, j] + 1, // deletion
- d[i, j-1] + 1, // insertion
- d[i-1, j-1] + cost // substitution
- )
- return d[m, n]
- --------------------------------代码结束----------------------------------
- Two examples of the resulting matrix (the minimum steps to be taken are highlighted):
- k i t t e n s i t t i n g
- 0 1 2 3 4 5 6
- 1 1 2 3 4 5 6
- 2 2 1 2 3 4 5
- 3 3 2 1 2 3 4
- 4 4 3 2 1 2 3
- 5 5 4 3 2 2 3
- 6 6 5 4 3 3 2
- 7 7 6 5 4 4 3 S a t u r d a y S u n d a y
- 0 1 2 3 4 5 6 7 8
- 1 0 1 2 3 4 5 6 7
- 2 1 1 2 2 3 4 5 6
- 3 2 2 2 3 3 4 5 6
- 4 3 3 3 3 4 3 4 5
- 5 4 3 4 4 4 4 3 4
- 6 5 4 4 5 5 5 4 3
- The invariant maintained throughout the algorithm is that we can transform the initial segment s[1..i] into t[1..j] using a minimum of d[i,j] operations. At the end, the bottom-right element of the array contains the answer.
- This algorithm is essentially part of a solution to the Longest common subsequence problem (LCS), in the particular case of 2 input lists.
- 这里使用动态规划不断计算他们间的距离,特别注意一下这里就可以了:
- d[i, j] := minimum(
- d[i-1, j] + 1, // deletion
- d[i, j-1] + 1, // insertion
- d[i-1, j-1] + cost // substitution
- )
- 三种情况代表了:,和前一个相等,和后一个相等,匹配(权衡三种情况代价最小的那种),最后矩阵右下角的数字就是两个字符串的距离,越小越相似!(这里加权的时候都是简单处理加1了事,实际上还可以细分处理,这种方法也不能很好地对两个字符刚好错位的情况进行处理)
- 这种思路就是最大公共子串的一个稍微不一样的扩展,背后的本质思想还是差不多的,所以我前面所说的不断计算矩阵斜线上连续数字的平方和也是一个意思,可以达到相同的效果。
- 编辑一点东西太麻烦了,又没有好一点的Blog,实在写不下去了 :( 矩阵表格格式的支持不好,然后用QQ截屏,居然只能保存为bmp格式,然后插入bmp格式上传结果搜狐不支持,然后想用工具(画板或者Google的 Picasa处理一下)未果,愤怒,不写了,快凌晨一点了,明天还要上班 :)
转自:http://9.douban.com/site/entry/24428719/
本文想从Office中的Word的语法检查和纠正功能发散开来,探讨一下这方面的相关算法和对问题的思考方式,以及怎么样从其他类似的地方受到启发不断解决新的问题。
先简单说说问题吧,我们在使用Word的时候经常会发现有些单词比如school,一不小心给敲成了shcool或者shool,这个时候Word会很体 贴地提示我们这个英语单词错了(很简单shcool,shool在Word的字典库中都没有出现过,所以肯定错了),接下来Word给出了好几个单词都长 得特别像shcool,让我们最快地修正错误,今天真正要讲的就是Word怎么判断两个字符串的相似程度(长的像)的(相似程度越高就越要给你推荐纠正)
下面涉及的算法有Spelling suggestion(拼写纠正算法)、Spell checker(拼写检查算法)、Bloom Filter(布隆过滤器)、longest common substring(最大公共子串),Levenshtein distance(我不知道怎么恰当的翻译,大概意思是计算一个字符串变到另一个字符串所需要的步骤吧,也就是两个字符串的相似程度,步骤越短当然越相似)
第一步Word肯定要能判断这个单词正确与否的,自然最合适的是使用布隆过滤器了(Bloom Filter), 其实布隆过滤器的原理很简单:通过Hash将所有正确的单词都记下来,然后再来了一个字符串的话,对它进行Hash,然后检查Hash出来的地址上有没有 记号,没有的话表示这个字符串在我们的正确单词库中没有任何单词能够和他匹配,那肯定就错了,这就是布隆过滤器的思想,但是你一想的话发现在我们的这个需 求中不需要在Hash表中存储正确单词的内容了(所以不需要能装下整个词典那么大的空间了),最简单用一个Bit表示(0表示没有,1表示有)这个位置上 有没有正确的单词就可以了,这样就节省了大量空间!毕竟这个需求比我们传统的使用Hash的时候要简单,所以没有理由为Key付出代价:),具体还可以参 考Google的吴军的数学之美系列文章,这样就达到了一个字符串是否为一个正确的单词了,不是的话就要接下来找一个最有可能的单词来推荐我们修正他。(到这里就完成了拼写检查的功能,当然Bloom Filter还有很多其他用处)
接下来在讲述如何判断两个字符窜的相似程度的时候我们先来看看另外一个问题(下面的内容是摘录自http://www.5do8.com/blog/doc/569/index.aspx):LCS(longest common substring)算法,即最大公共子串,它是求两个字符串最长公共子串的问题(就是两个字符串中最长的公共部分)。大体解法是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0。然后求出对角线(确切来说是矩阵斜线)最长的1序列,其对应的位置就是最长匹配子串的位置.
例如,有两个字符串:
A= I MISS MY CODE HI
B= One Like MY Code
这里,先忽略掉大小写,通吃,在C#或者PHP中,String.ToLower()或者lower()可以考虑.对于其中的特殊字符,例如空格,可以在比较的时候直接删除.另外,该算法比较与顺序无关,可以随意的翻转字符串.接下来比较.
i m i s s m y c o d e h i
o 0 0 0 0 0 0 0 0 1 0 0 0 0
n 0 0 0 0 0 0 0 0 0 0 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0
l 0 0 0 0 0 0 0 0 0 0 0 0 0
i 1 0 1 0 0 0 0 0 0 0 0 0 1
k 0 0 0 0 0 0 0 0 0 0 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0
m 0 1 0 0 0 1 0 0 0 0 0 0 0
y 0 0 0 0 0 0 1 0 0 0 0 0 0
c 0 0 0 0 0 0 0 1 0 0 0 0 0
o 0 0 0 0 0 0 0 0 1 0 0 0 0
d 0 0 0 0 0 0 0 0 0 1 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0
在上面的矩阵图中,其中的红色(最长的1串)就可以看成匹配的字符串. (摘录完毕)
或者这样标示矩阵会更方便:
i m i s s m y c o d e h i
o 0 0 0 0 0 0 0 0 1 0 0 0 0
n 0 0 0 0 0 0 0 0 0 0 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0
l 0 0 0 0 0 0 0 0 0 0 0 0 0
i 1 0 1 0 0 0 0 0 0 0 0 0 1
k 0 0 0 0 0 0 0 0 0 0 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0
m 0 1 0 0 0 1 0 0 0 0 0 0 0
y 0 0 0 0 0 0 2 0 0 0 0 0 0
c 0 0 0 0 0 0 0 3 0 0 0 0 0
o 0 0 0 0 0 0 0 0 4 0 0 0 0
d 0 0 0 0 0 0 0 0 0 5 0 0 0
e 0 0 0 0 0 0 0 0 0 0 6 0 0
最大数字是6,所以最长公共子串的长度是6,开始位置可以从6所在的位置推算出来(i-6,j-6)就可以了
好了这个问题到这里是完美优美地解决了,非常好理解,我当时反正感觉非常是受震撼(其实我每次看到好算法都是这样的)然后就琢磨了这个算法背后的原理、思 想是什么它还能应用在哪些方面,正好我以前做个一个算法这么样计算两个字符串的匹配程度(当时是用匹配度不断加权计算出来的相似度,并进行了一些特殊处理 才马马虎虎对特殊情况非常合适,呵呵太弱了吧),感觉这两个问题特别相似,既然这个矩阵记录了所有的匹配情况,那么我可以这样想所有斜线(平行对角线)上 的数字加起来平方,这样得到一个数字,越大的话应该是两个字符串在不同的地方匹配整体匹配度越高(画图实在不方便,我不知道大家理解我的意思了没有,呵 呵,当时我是这样想的)。因为虽然LCS算法解决的只是最长公共子串的问题,但是这个算法还帮我们得到了所有其他地方匹配的公共子串(不是最长的那些,当 然也要在相似度中纳入计算的),所以我觉得这个想法是在LCS原理上的一个拓展,同样是成立的。
接下来我们再来看看拼写纠正的时候先进行的相似度判断:Levenshtein distance (下面的例子和伪代码摘自Wiki:Levenshtein distance,非常简单我就偷懒了,要我画出这个图形简直是太不可能了,好麻烦的):
A commonly-used bottom-up dynamic programming algorithm for computing the Levenshtein distance involves the use of an (n + 1) × (m + 1) matrix, where n and m are the lengths of the two strings. This algorithm is based on the Wagner-Fischer algorithm for edit distance. Here is pseudocode for a function LevenshteinDistance that takes two strings, s of length m, and t of length n, and computes the Levenshtein distance between them:
int LevenshteinDistance(char s[1..m], char t[1..n])
// d is a table with m+1 rows and n+1 columns
declare int d[0..m, 0..n]
for i from 0 to m
d[i, 0] := i
for j from 1 to n
d[0, j] := j
for i from 1 to m
for j from 1 to n
if s[i] = t[j] then cost := 0
else cost := 1
d[i, j] := minimum(
d[i-1, j] + 1, // deletion
d[i, j-1] + 1, // insertion
d[i-1, j-1] + cost // substitution
)
return d[m, n]
--------------------------------代码结束----------------------------------
Two examples of the resulting matrix (the minimum steps to be taken are highlighted):
k i t t e n s i t t i n g
0 1 2 3 4 5 6
1 1 2 3 4 5 6
2 2 1 2 3 4 5
3 3 2 1 2 3 4
4 4 3 2 1 2 3
5 5 4 3 2 2 3
6 6 5 4 3 3 2
7 7 6 5 4 4 3 S a t u r d a y S u n d a y
0 1 2 3 4 5 6 7 8
1 0 1 2 3 4 5 6 7
2 1 1 2 2 3 4 5 6
3 2 2 2 3 3 4 5 6
4 3 3 3 3 4 3 4 5
5 4 3 4 4 4 4 3 4
6 5 4 4 5 5 5 4 3
The invariant maintained throughout the algorithm is that we can transform the initial segment s[1..i] into t[1..j] using a minimum of d[i,j] operations. At the end, the bottom-right element of the array contains the answer.
This algorithm is essentially part of a solution to the Longest common subsequence problem (LCS), in the particular case of 2 input lists.
这里使用动态规划不断计算他们间的距离,特别注意一下这里就可以了:
d[i, j] := minimum(
d[i-1, j] + 1, // deletion
d[i, j-1] + 1, // insertion
d[i-1, j-1] + cost // substitution
)
三种情况代表了:,和前一个相等,和后一个相等,匹配(权衡三种情况代价最小的那种),最后矩阵右下角的数字就是两个字符串的距离,越小越相似!(这里加权的时候都是简单处理加1了事,实际上还可以细分处理,这种方法也不能很好地对两个字符刚好错位的情况进行处理)
这种思路就是最大公共子串的一个稍微不一样的扩展,背后的本质思想还是差不多的,所以我前面所说的不断计算矩阵斜线上连续数字的平方和也是一个意思,可以达到相同的效果。
编辑一点东西太麻烦了,又没有好一点的Blog,实在写不下去了 :( 矩阵表格格式的支持不好,然后用QQ截屏,居然只能保存为bmp格式,然后插入bmp格式上传结果搜狐不支持,然后想用工具(画板或者Google的 Picasa处理一下)未果,愤怒,不写了,快凌晨一点了,明天还要上班 :)
5. { aaa, bb, ccc, dd }, { bbb, ff }, { gg } 等一些字符串的集合
要求把交集不为空的集合并起来,如上例会得到 { aaa, bb, ccc, dd, ff }, {gg}
(1) 思想 (2) 算法及复杂度 (3) 改进