在數學中,某個序列的子串行是從最初序列通過去除某些元素但不破壞餘下元素的相對位置(在前或在後)而形成的新序列。比如:abcdefghi的乙個子串行是adfgi。
理解了子串行就能簡單的理解最長公共子串行。就是對於兩個序列,有乙個序列三滿足既是序列1的子串行也是序列2的子串行而且是滿足這個條件的子串行中最長的乙個,它就是序列1,2的最長公共子串行。
比如:bdcaba和abcbdab的最長公共子串行就是bcba。
最長公共子串行(longest common subsequence, lcs)是一道非常經典的動態規劃題,要學這個最好先對動態規劃有一定了解。設:s
tr1=
a0a1
...a
n ,st
r2=b
0b1.
..bm
,它們的最長公共子串行為st
r=c0
c1..
.ck
我們來看看怎麼推出狀態轉移方程
首先,不難得出如下結論:
1. 如果an
=bm ,那麼ck
=an=
bm且c0.
..ck
−1是a0.
..an
−1和b0.
..bm
−1的最長公共子串行。(感覺運用了分治的思想)
2. 如果an
!= bm
,那麼c0
...c
k 是max(lcs(a0
...a
n−1 ,b0
...b
m ),lcs(a0
...a
n ,b0
...b
m−1 ))那乙個的最長公共子串行。
由上述結論,我們設dp[i][j]為a0
...a
i 和b0
...b
j 的最長公共子串行的長度。所以: dp
[i][
j]=⎧
⎩⎨0d
p[i−
1][j
−1]+
1max
(dp[
i−1]
[j],
dp[i
][j−
1])i=0 || j=0
i,j>0 && ai
=bji,j>0 && ai
!= bj
以bdcaba和abcbdab為例,我們看看它的遞推過程
int lcs(char *str1, char *str2)
}return dp[len1][len2];
}
給出兩個字串,求出其最長公共子串行及其長度。
**:
#include
using namespace std;
#define time_ (printf("%.6f\n", double(clock())/clocks_per_sec))
typedef long long ll;
const int maxn = 1e3+5;
int dp[maxn][maxn];
//記錄dp[i][j]是從哪遞推過來的
//-1是dp[i-1][j-1],0是dp[i][j-1],1是dp[i-1][j]
這裡為什麼是bdab而不是我上面遞推圖中的bcba,大家可以看我**思考一下,應該很容易思考出來。
其實是else if(dp[i][j-1]>dp[i-1][j])這一句的問題。
LCS 最長公共子串行
問題描述 我們稱序列z z1,z2,zk 是序列x x1,x2,xm 的子串行當且僅當存在嚴格上 公升的序列 i1,i2,ik 使得對 j 1,2,k,有 xij zj。比如z a,b,f,c 是 x a,b,c,f,b,c 的子串行。現在給出兩個序列 x和 y,你的任務是找到 x和 y的最大公共子...
LCS最長公共子串行
求兩個字串的最大公共子串行問題 子串行的定義 若給定序列x 則另一串行z 是x的子串行是指存在乙個嚴格遞增下標序列使得對於所有j 1,2,k有 zj xij。例如,序列z 是序列x 的子序列,相應的遞增下標序列為。分析 用動態規劃做 1.最長公共子串行的結構 事實上,最長公共子串行問題具有最優子結構...
LCS最長公共子串行
lcs是longest common subsequence的縮寫,即最長公共子串行。乙個序列,如果是兩個或多個已知序列的子串行,且是所有子串行中最長的,則為最長公共子串行。複雜度對於一般的lcs問題,都屬於np問題。當數列的量為一定的時,都可以採用動態規劃去解決。解法動態規劃的乙個計算最長公共子串...