动态规划(一)最长公共子序列
- 动态规划与分治法
- 什么是最长公共子序列
- 利用动态规划法求两字符串的最长子序列的长度
- 回溯法获得两字符串的最长子序列
- java代码
一、动态规划(dynamic programming)
与分治法类似,都是通过组合子问题的解来求原问题的解。
两者区别:
- 分治法把问题划分为不相交的子问题;动态规划应用于子问题重叠的情况;
- 分治法常用递归(因为子问题处理方式相同);动态规划不采用递归(子问题重叠,采用递归会有许多不必要的计算);
动态规划一般采用表格来获得结果。
二、两字符串的最长公共子序列
一个数列 ,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 称为已知序列的最长公共子序列。
例如:
String s1 = "abcddfeab";
String s2 = "bcdfa";
s1和s2的最长公共子序列common 为“bcdfa”,最长公共子序列可以不连续(在s1中common不是连续的),只需要保持相对前后位置即可(在s1中c在b之后,d在bc之后,以此类推)。最长公共子序列表示两个字符串前后顺序相对一致的部分。
三、利用动态规划法求两字符串的最长公共子序列的长度
最长公共序列:longest common sequence(LCS)
int m = s1.length;//此处为9
int n = s2.length;//此处为5
求两字符串的LCS长度的表格如下所示:
* | * | b | c | d | f | a |
---|---|---|---|---|---|---|
* | 0 | 0 | 0 | 0 | 0 | 0 |
a | 0 | 0 | 0 | 0 | 0 | 1 |
b | 0 | 1 | 1 | 1 | 1 | 1 |
c | 0 | 1 | 2 | 2 | 2 | 2 |
d | 0 | 1 | 2 | 3 | 3 | 3 |
d | 0 | 1 | 2 | 3 | 3 | 3 |
f | 0 | 1 | 2 | 3 | 4 | 4 |
e | 0 | 1 | 2 | 3 | 4 | 4 |
a | 0 | 1 | 2 | 3 | 4 | 5 |
b | 0 | 1 | 2 | 3 | 4 | 5 |
首先创建m+1行n+1列的矩阵arr,如上表,第0行第0列置为0。
从arr[1][1]开始计算:
arr[1][1]表示a(arr[1][1]横行所对应的字符及以上)和b(arr[1][1]竖行所对应的字符及以前)的LCS长度,由于a和b不相等,因此arr[1][1]为0;
再按行计算arr[1][2]:
表示字符a和bc(arr[1][2]竖行所对应的的字符及以前)的LCS长度,依旧不相等,arr[1][2]为0;
… …
计算第2行:
arr[2][1]表示ab和b的LCS长度,有重复字符b,因此arr[2][1]为1;
… …
计算第三行:
arr[3][1] = 1;//abc和b的LCS长度
arr[3][2] = 2;//abc和bc的LCS长度
… …
该表格中的arr[m][n]即为字符串s1和s2的LCS长度。
由上述表格可以归纳出arr[i][j]的递归表达式:
arr[i,j]