生活随笔
收集整理的這篇文章主要介紹了
算法:最长公共子序列(输出所有最长公共子序列)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
問題描述:給定兩個序列,例如 X = “ABCBDAB”、Y = “BDCABA”,求它們的最長公共子序列的長度。
下面是求解時的動態規劃表,可以看出 X 和 Y 的最長公共子序列的長度為4:
輸出一個最長公共子序列并不難(網上很多相關代碼),難點在于輸出所有的最長公共子序列,因為 LCS 通常不唯一。
我們需要在動態規劃表上進行回溯 —— 從c
[m
][n
],即右下角的格子,開始進行判斷:如果格子c
[i
][j
]對應的X
[i-1
] == Y
[j-1
],則把這個字符放入 LCS 中,并跳入c
[i-1
][j-1
]中繼續進行判斷;如果格子c
[i
][j
]對應的 X
[i-1
] ≠ Y
[j-1
],則比較c
[i-1
][j
]和c
[i
][j-1
]的值,跳入值較大的格子繼續進行判斷;如果出現c
[i-1
][j
]等于c
[i
][j-1
]的情況,說明最長公共子序列有多個,故兩邊都要進行回溯(這里用到遞歸)。直到 i 或 j 小于等于零為止,倒序輸出 LCS 。
從上圖的紅色路徑顯示,X 和 Y 的最長公共子序列有 3 個,分別為 “BDAB”、“BCAB”、“BCBA”。
C++代碼:
#include<bits/stdc++.h>
using namespace std
;string X
;
string Y
;
vector
<vector
<int> > c
;
set
<string
> lcs
; int lcs_length(int m
, int n
)
{c
= vector
<vector
<int> >(m
+1,vector
<int>(n
+1));for(int i
=0; i
<m
+1; ++i
){for(int j
=0; j
<n
+1; ++j
){if (i
== 0 || j
== 0)c
[i
][j
] = 0;else if(X
[i
-1] == Y
[j
-1])c
[i
][j
] = c
[i
-1][j
-1] + 1;elsec
[i
][j
] = max(c
[i
-1][j
], c
[i
][j
-1]);}}return c
[m
][n
];
}void lcs_print(int i
, int j
, string lcs_str
)
{while (i
>0 && j
>0){if (X
[i
-1] == Y
[j
-1]){lcs_str
.push_back(X
[i
-1]);
--i
;--j
;}else{if (c
[i
-1][j
] > c
[i
][j
-1])--i
;else if (c
[i
-1][j
] < c
[i
][j
-1])--j
;else{lcs_print(i
-1, j
, lcs_str
);lcs_print(i
, j
-1, lcs_str
);return;}}}
reverse(lcs_str
.begin(),lcs_str
.end());lcs
.insert(lcs_str
);
}int main()
{cin
>>X
>>Y
;int m
= X
.length();int n
= Y
.length();int length
= lcs_length(m
, n
);cout
<< "The length of LCS is " << length
<< endl
;string str
;lcs_print(m
, n
, str
);set
<string
>::iterator it
= lcs
.begin();for( ; it
!=lcs
.end(); it
++)cout
<< *it
<< endl
;return 0;
}
運行效果:
總結
以上是生活随笔為你收集整理的算法:最长公共子序列(输出所有最长公共子序列)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。