百度2005年面試題

百度2005年的筆試題




1.實現 void delete_char(char * str, char ch);
 把str中所有的ch刪掉
  1. #include <iostream>   
  2. #include <stack>   
  3. using namespace std;  
  4.   
  5. void delete_char(char *str, char ch)  
  6. {  
  7.     int i,j;  
  8.     i = j = 0;  
  9.     while(str[i])  
  10.     {  
  11.         if(str[i] != ch)  
  12.         {  
  13.             str[j++] = str[i++];  
  14.         }else  
  15.             i++;  
  16.     }  
  17.     str[j] = '\0';  
  18. }  
  19.   
  20.   
  21. int main()  
  22. {  
  23.     char str[]= "abccbaccab";  
  24.     delete_char(str, 'c');  
  25.     cout << str << endl;  
  26. }  
#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
  1. 轉自: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   
  2.   
  3. #include <stdio.h>   
  4. #include <stdlib.h>   
  5. #include <string.h>   
  6.   
  7. int get_next(char* t,int next[])  
  8. {  
  9.   int i = 0;  
  10.   int k = -1;  
  11.   int len = strlen(t);  
  12.    next[0] = k;  
  13.     
  14.   while(i<len-1)  
  15.   {  
  16.    if( k==-1 || t[i]==t[k] )  
  17.      {  
  18.        k++;  
  19.        i++;  
  20.       if(t[i] != t[k])  
  21.          next[i] = k;  
  22.       else  
  23.          next[i] = next[k];   
  24.       }  
  25.     else  
  26.        k = next[k];   
  27.    }   
  28. }  
  29.   
  30. int kmp_find(char* s,char* t)  
  31. {  
  32.   int i = 0;  
  33.   int j = 0;  
  34.   int len1 = strlen(s);   
  35.   int len2 = strlen(t);   
  36.   int next[len2];  
  37.    get_next(t,next);  
  38.     
  39.   while(i<len1 && j<len2)   
  40.    {  
  41.      if( j==-1 || s[i] == t[j])  
  42.       {  
  43.         i++;  
  44.         j++;  
  45.       }  
  46.      else  
  47.        j = next[j];   
  48.    }  
  49.      
  50.    if(j>=len2)  
  51.      return i-len2;  
  52.    else  
  53.    return -1;  
  54. }  
  55.   
  56. char* substr(char* s,char* a,char* b)  
  57. {  
  58.     int len = strlen(a);  
  59.       
  60.     int index = kmp_find(s,a);  
  61.     //kmp find where is a in s or you can use strstr   
  62.     char* head = s;  
  63.     *(head+index) = '\0';  
  64.     char* tail = s + index + len;  
  65.     //把字符串s分爲 head a tail三部分   
  66.     sprintf(s,"%s%s%s",head,b,tail);  
  67.     
  68.     if(kmp_find(s,a) != -1)//如果替換一個後還含有a繼續   
  69.      return substr(s, a, b);  
  70.     else  
  71.      return s;  
  72. }  
  73.        
  74. int main(int argc, char *argv[])  
  75. {  
  76.   char* s = (char*)malloc(100);  
  77.   memset(s,0,100);  
  78.   sprintf(s,"%s",argv[1]);  
  79.   
  80.   printf("str:%s\n",s);   
  81.   printf("sub:%s by %s\nafter:%s\n",argv[2],argv[3],substr(s, argv[2], argv[3]));  
  82.   
  83.   free(s);  
  84.    s=NULL;  
  85.   system("PAUSE");      
  86.   return 0;  
  87. }  
  88. 贈送shell實現  
  89. echo "xxxxxx" | sed 's/xxx/xxx/g'  
  90. awk -v str="sadsadas" 'BEGIN{gsub(/xxx/,"xxxxx",str);print str}'  
  91. vi ed等edit內直接s/xx/xxx/g  
  92. 玩笑的呵呵...  
轉自: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) 算法及其複雜度分析
  1. //未完待續   
  2.   
  3. //基本思路:   
  4. #include <iostream>   
  5. #include <fstream>   
  6. #include <map>   
  7. #include <string>   
  8. using namespace std;  
  9.   
  10. string* topTen()  
  11. {  
  12.     ifstream fin("test.txt");  
  13.     if(!fin)  
  14.     {  
  15.         exit(0);  
  16.     }  
  17.     map<string, int> m;  
  18.     string s;  
  19.     while(fin >> s)  
  20.     {  
  21.         m[s] ++;  
  22.     }  
  23.     string heap[10];  
  24.     int c = 0;  
  25.     for(map<string,int>::iterator it = m.begin(); it!= m.end();it++)  
  26.     {  
  27.         if(c < 10)  
  28.   
  29.     }  
  30. }  
  31.   
  32.   
  33. int main()  
  34. {  
  35.       
  36. }  
//未完待續

//基本思路:
#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) 改進
  1. 轉自:http://9.douban.com/site/entry/24428719/   
  2.   
  3. 本文想從Office中的Word的語法檢查和糾正功能發散開來,探討一下這方面的相關算法和對問題的思考方式,以及怎麼樣從其他類似的地方受到啓發不斷解決新的問題。  
  4.     先簡單說說問題吧,我們在使用Word的時候經常會發現有些單詞比如school,一不小心給敲成了shcool或者shool,這個時候Word會很體 貼地提示我們這個英語單詞錯了(很簡單shcool,shool在Word的字典庫中都沒有出現過,所以肯定錯了),接下來Word給出了好幾個單詞都長 得特別像shcool,讓我們最快地修正錯誤,今天真正要講的就是Word怎麼判斷兩個字符串的相似程度(長的像)的(相似程度越高就越要給你推薦糾正)  
  5.   
  6.     下面涉及的算法有Spelling suggestion(拼寫糾正算法)、Spell checker(拼寫檢查算法)、Bloom Filter(布隆過濾器)、longest common substring(最大公共子串),Levenshtein distance(我不知道怎麼恰當的翻譯,大概意思是計算一個字符串變到另一個字符串所需要的步驟吧,也就是兩個字符串的相似程度,步驟越短當然越相似)  
  7.   
  8.     第一步Word肯定要能判斷這個單詞正確與否的,自然最合適的是使用布隆過濾器了(Bloom Filter), 其實布隆過濾器的原理很簡單:通過Hash將所有正確的單詞都記下來,然後再來了一個字符串的話,對它進行Hash,然後檢查Hash出來的地址上有沒有 記號,沒有的話表示這個字符串在我們的正確單詞庫中沒有任何單詞能夠和他匹配,那肯定就錯了,這就是布隆過濾器的思想,但是你一想的話發現在我們的這個需 求中不需要在Hash表中存儲正確單詞的內容了(所以不需要能裝下整個詞典那麼大的空間了),最簡單用一個Bit表示(0表示沒有,1表示有)這個位置上 有沒有正確的單詞就可以了,這樣就節省了大量空間!畢竟這個需求比我們傳統的使用Hash的時候要簡單,所以沒有理由爲Key付出代價:),具體還可以參 考Google的吳軍的數學之美系列文章,這樣就達到了一個字符串是否爲一個正確的單詞了,不是的話就要接下來找一個最有可能的單詞來推薦我們修正他。(到這裏就完成了拼寫檢查的功能,當然Bloom Filter還有很多其他用處)  
  9.   
  10.     接下來在講述如何判斷兩個字符竄的相似程度的時候我們先來看看另外一個問題(下面的內容是摘錄自http://www.5do8.com/blog/doc/569/index.aspx):LCS(longest common substring)算法,即最大公共子串,它是求兩個字符串最長公共子串的問題(就是兩個字符串中最長的公共部分)。大體解法是用一個矩陣來記錄兩個字符串中所有位置的兩個字符之間的匹配情況,若是匹配則爲1,否則爲0。然後求出對角線(確切來說是矩陣斜線)最長的1序列,其對應的位置就是最長匹配子串的位置.   
  11.   
  12. 例如,有兩個字符串:  
  13.   
  14. A= I MISS MY CODE HI  
  15.   
  16. B= One Like MY Code  
  17.   
  18. 這裏,先忽略掉大小寫,通吃,在C#或者PHP中,String.ToLower()或者lower()可以考慮.對於其中的特殊字符,例如空格,可以在比較的時候直接刪除.另外,該算法比較與順序無關,可以隨意的翻轉字符串.接下來比較.  
  19.   
  20. i   m   i   s   s   m   y   c   o   d   e   h   i  
  21. o   0   0   0   0   0   0   0   0   1   0   0   0   0  
  22. n   0   0   0   0   0   0   0   0   0   0   0   0   0  
  23. e   0   0   0   0   0   0   0   0   0   0   1   0   0  
  24. l   0   0   0   0   0   0   0   0   0   0   0   0   0  
  25. i   1   0   1   0   0   0   0   0   0   0   0   0   1  
  26. k   0   0   0   0   0   0   0   0   0   0   0   0   0  
  27. e   0   0   0   0   0   0   0   0   0   0   1   0   0  
  28. m   0   1   0   0   0   1   0   0   0   0   0   0   0  
  29. y   0   0   0   0   0   0   1   0   0   0   0   0   0  
  30. c   0   0   0   0   0   0   0   1   0   0   0   0   0  
  31. o   0   0   0   0   0   0   0   0   1   0   0   0   0  
  32. d   0   0   0   0   0   0   0   0   0   1   0   0   0  
  33. e   0   0   0   0   0   0   0   0   0   0   1   0   0  
  34.    在上面的矩陣圖中,其中的紅色(最長的1串)就可以看成匹配的字符串. (摘錄完畢)  
  35.   
  36. 或者這樣標示矩陣會更方便:  
  37.   
  38. i   m   i   s   s   m   y   c   o   d   e   h   i  
  39. o   0   0   0   0   0   0   0   0   1   0   0   0   0  
  40. n   0   0   0   0   0   0   0   0   0   0   0   0   0  
  41. e   0   0   0   0   0   0   0   0   0   0   1   0   0  
  42. l   0   0   0   0   0   0   0   0   0   0   0   0   0  
  43. i   1   0   1   0   0   0   0   0   0   0   0   0   1  
  44. k   0   0   0   0   0   0   0   0   0   0   0   0   0  
  45. e   0   0   0   0   0   0   0   0   0   0   1   0   0  
  46. m   0   1   0   0   0   1   0   0   0   0   0   0   0  
  47. y   0   0   0   0   0   0   2   0   0   0   0   0   0  
  48. c   0   0   0   0   0   0   0   3   0   0   0   0   0  
  49. o   0   0   0   0   0   0   0   0   4   0   0   0   0  
  50. d   0   0   0   0   0   0   0   0   0   5   0   0   0  
  51. e   0   0   0   0   0   0   0   0   0   0   6   0   0  
  52. 最大數字是6,所以最長公共子串的長度是6,開始位置可以從6所在的位置推算出來(i-6,j-6)就可以了  
  53.     好了這個問題到這裏是完美優美地解決了,非常好理解,我當時反正感覺非常是受震撼(其實我每次看到好算法都是這樣的)然後就琢磨了這個算法背後的原理、思 想是什麼它還能應用在哪些方面,正好我以前做個一個算法這麼樣計算兩個字符串的匹配程度(當時是用匹配度不斷加權計算出來的相似度,並進行了一些特殊處理 才馬馬虎虎對特殊情況非常合適,呵呵太弱了吧),感覺這兩個問題特別相似,既然這個矩陣記錄了所有的匹配情況,那麼我可以這樣想所有斜線(平行對角線)上 的數字加起來平方,這樣得到一個數字,越大的話應該是兩個字符串在不同的地方匹配整體匹配度越高(畫圖實在不方便,我不知道大家理解我的意思了沒有,呵 呵,當時我是這樣想的)。因爲雖然LCS算法解決的只是最長公共子串的問題,但是這個算法還幫我們得到了所有其他地方匹配的公共子串(不是最長的那些,當 然也要在相似度中納入計算的),所以我覺得這個想法是在LCS原理上的一個拓展,同樣是成立的。  
  54.   
  55.     接下來我們再來看看拼寫糾正的時候先進行的相似度判斷:Levenshtein distance (下面的例子和僞代碼摘自Wiki:Levenshtein distance,非常簡單我就偷懶了,要我畫出這個圖形簡直是太不可能了,好麻煩的):  
  56.   
  57.      
  58.   
  59. 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:  
  60.   
  61. int LevenshteinDistance(char s[1..m], char t[1..n])  
  62.    // d is a table with m+1 rows and n+1 columns   
  63.    declare int d[0..m, 0..n]  
  64.    
  65.    for i from 0 to m  
  66.        d[i, 0] := i  
  67.    for j from 1 to n  
  68.        d[0, j] := j  
  69.    
  70.    for i from 1 to m  
  71.        for j from 1 to n  
  72.            if s[i] = t[j] then cost := 0  
  73.                           else cost := 1  
  74.            d[i, j] := minimum(  
  75.                                 d[i-1, j] + 1,     // deletion   
  76.                                 d[i, j-1] + 1,     // insertion   
  77.                                 d[i-1, j-1] + cost   // substitution   
  78.                             )  
  79.    
  80.    return d[m, n]  
  81. --------------------------------代碼結束----------------------------------  
  82. Two examples of the resulting matrix (the minimum steps to be taken are highlighted):  
  83.   
  84. k i t t e n s i t t i n g  
  85. 0   1   2   3   4   5   6  
  86. 1   1   2   3   4   5   6  
  87. 2   2   1   2   3   4   5  
  88. 3   3   2   1   2   3   4  
  89. 4   4   3   2   1   2   3  
  90. 5   5   4   3   2   2   3  
  91. 6   6   5   4   3   3   2  
  92. 7   7   6   5   4   4   3    S a t u r d a y S u n d a y  
  93. 0   1   2   3   4   5   6   7   8  
  94. 1   0   1   2   3   4   5   6   7  
  95. 2   1   1   2   2   3   4   5   6  
  96. 3   2   2   2   3   3   4   5   6  
  97. 4   3   3   3   3   4   3   4   5  
  98. 5   4   3   4   4   4   4   3   4  
  99. 6   5   4   4   5   5   5   4   3  
  100. 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.  
  101.   
  102. This algorithm is essentially part of a solution to the Longest common subsequence problem (LCS), in the particular case of 2 input lists.  
  103.   
  104. 這裏使用動態規劃不斷計算他們間的距離,特別注意一下這裏就可以了:  
  105.   
  106. d[i, j] := minimum(  
  107.                                 d[i-1, j] + 1,     // deletion   
  108.                                 d[i, j-1] + 1,     // insertion   
  109.                                 d[i-1, j-1] + cost   // substitution   
  110.                             )  
  111. 三種情況代表了:,和前一個相等,和後一個相等,匹配(權衡三種情況代價最小的那種),最後矩陣右下角的數字就是兩個字符串的距離,越小越相似!(這裏加權的時候都是簡單處理加1了事,實際上還可以細分處理,這種方法也不能很好地對兩個字符剛好錯位的情況進行處理)  
  112.   
  113.     這種思路就是最大公共子串的一個稍微不一樣的擴展,背後的本質思想還是差不多的,所以我前面所說的不斷計算矩陣斜線上連續數字的平方和也是一個意思,可以達到相同的效果。  
  114.   
  115.     編輯一點東西太麻煩了,又沒有好一點的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) 改進




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章