對乙個序列x和另乙個序列y,兩者的最長公共序列是,兩者最長的公共子串是
最長公共子串要求連續
用動態規劃實現最重要的是要找到遞迴方程或者迭代方程,只要把這個方程找出來了,對著這個方程想個幾十分鐘,就可以把**寫出來,然後再拿例子測試,寫出來的**基本就沒問題了。
也許你第一次接觸「如何將方程轉化為**」的問題,感覺無從下手,這很正常。只要寫得多了,將方程轉化為**其實並不困難。
困難的是如何根據問題找到那個方程,這涉及到將問題抽象為數學問題。
求最長公共子串行的遞迴方程如下,那麼這個方程是如何得出來的呢?
例如,在求長度為m的序列x和長度為n的序列y的最長公共子串行長度c[m,n]時,可以假設它們的上一條件下的結果是已知的。
下面我們要開始窮舉上一條件下的所有結果,在窮舉這些結果的基礎上給出方程。
這裡有兩個變數,序列x的長度m和序列y的長度n,所以上一條件下的結果有三個m-1,n-1,m-1且n-1。由這三個結果可以推出其他所有結果。
當m-1時,序列x要增加乙個新的字元,只有當新增加的字元為k的時候(準確來說或是y中d以後的字元,即xm=yd),最長公共子串行的長度c才會加1,否則長度c不變。那麼c[m,n]>=c[m-1,n]。
當n-1時,序列y要增加乙個新的字元,只有當新增加的字元為f的時候(xd=yn),最長公共子串行的長度c才會加1,否則長度c不變。那麼c[m,n]>=c[m,n-1]。
當m-1,n-1時,有以下可能:序列x和序列y增加了相同的字元(xm=yn),那麼長度c加1;序列x增加了k,序列y增加了f,那麼長度c加1,相當於m-1時或者相當於n-1時;序列x增加了k,序列y增加的不是f,長度c加1,相當於m-1時;序列x增加的不是k,序列y增加是f,那麼長度c加1,相當於n-1時;序列x增加的不是k,序列y增加的不是f,那麼長度c不變。那麼c[m,n]>=c[m-1,n-1]。
所以有:
如果xm=yn,則c[m,n]=c[m-1,n-1]+1;如果xm≠yn,c[m,n]=c[m-1,n]或者c[n-1,m]中大的那乙個,如果兩者相等,隨便選取乙個。考慮空序列,那麼m=0或者n=0時,c[m,n]=0。
【最長公共子串行長度】
上文中m和n表示字串的長度,對c[m,n]的二維陣列來說,其大小實際上是m+1,n+1。c[m,n]的值就是最長公共子串行的長度。
【輸出最長公共子串行】
建立乙個標記二維資料mark,如果xm=yn,表示xm或者yn是最長公共子串行的乙個字元,那麼mark[m,n]=1。如果c[m-1,n]>=c[m,n-1]時,mark[m,n]=2。c[m-1,n]【輸出所有最長公共子串行】
當c[m-1,n]=c[n-1,m]時,可以隨機選取乙個,這就造成了路徑的差別,即可以由c[m-1,n]向右加1到c[m,n],也可以由c[m,n-1]向下加1到c[m,n]。反之,在c[m,n]處相當於有了個路口,可以向左走到c[m-1,n],也可以向上走到c[m,n],我們要把這個路口標記下來。先向左走,走到頭後(即m=0或者n=0)回到起點,再經過這個路口後向右走。
【求最長公共子串】
最長公共子串要求連續,那麼如果xm≠yn,則子串就斷開了,我們把這裡標記為0。找到二維陣列c中的最大值,即為最長公共子串的長度。標記最大值時的m或者n,就知道子串的最後乙個字元位於在序列x或者y中的位置。
using system;
using system.collections.generic;
namespace lcs
console.writeline(" ");
//輸出所有最長公共子串行
pr.printalllcs(str3,str4);
console.writeline(" ");
string str;
//求最長公共子串長度並輸出
int len = pr.longestcommonsubstring(str5, str6,out str);
console.writeline(len+" "+str);
console.readkey();
}public int longestcommonsubsequence(string str1, string str2,out stacklcs )
int m = str1.length + 1;
int n = str2.length + 1;
int[,] c=new int[m, n];
int[,] mark=new int[m, n];
for (int i = 1; i < m; i++)
else if(c[i-1,j]>=c[i,j-1])//兩者相等時取左邊的
else}}
lcs=new stack();
for (int i = m-1,j=n-1; i >=0&&j>=0;)
else if(mark[i, j] == 2)
else
}return c[str1.length, str2.length];
}public void printalllcs(string str1, string str2)
int m = str1.length + 1;
int n = str2.length + 1;
int[,] c = new int[m, n];
for (int i = 1; i < m; i++)
else if (c[i - 1, j] >= c[i, j - 1])
else}}
stacklcs = new stack();
dictionarymark=new dictionary();
for (int i = m - 1, j = n - 1; i >= 1 && j >= 1;)
else if (c[i - 1, j] > c[i, j - 1])//向左走
else if (c[i - 1, j] < c[i, j - 1]) //向上走
else
else
}if (i < 1 || j < 1)
if(reset)//只要有乙個位置的路口沒有為true,就表明沒有走完,回到起點重新走}}
動態規劃 最長公共子串行與最長公共子串
子串應該比較好理解,至於什麼是子串行,這裡給出乙個例子 有兩個母串 比如序列bo,bg,lg在母串cnblogs與belong中都出現過並且出現順序與母串保持一致,我們將其稱為公共子串行。最長公共子串行 longest common subsequence,lcs 顧名思義,是指在所有的子串行中最長...
動態規劃之最長公共子串行 最長公共子串
題目 如果字串1的所有字元按其在字串中的順序出現在另外乙個字串2中,則字串1稱之為字串2的子串行。注意,並不要求子子串行 字串1 的字元必須連續出現在字串2中。請編寫乙個函式,輸入兩個字串,求它們的最長公共子串,並列印出最長公共子串行。例如 輸入兩個字串bdcaba和abcbdab,字串bcba和b...
動態規劃 最長公共子串行和最長公共子串
我們首先需要搞清楚以下兩個概念 最長公共子串行 vs 最長公共子串 找兩個字串的最長公共子串,這個子串要求在原字串中是連續的。而最長公共子串行則並不要求連續。問題描述 給定兩個字串,求解這兩個字串的最長公共子串行 longest common sequence 比如字串1 bdcaba 字串2 ab...