问题描述
参考
coursera-北京大学-算法基础-动态规划(1)-几个例题
笔记
动态规划问题,同样要建表。
buff[i][j]表示以字符串A的第i位结束,以字符串B的第j位结束,的最长公共子序列。
状态转移方程:
if (A[i] == B[j])
buff[i][j] = buff[i-1][j-1] + 1;
else
buff[i][j] = max(buff[i-1][j], buff[i][j-1]);
解释:
规定:
S[i][j]的含义是<以A的第i位结尾的字符串>与<以B的第j位结尾的字符串>的最长公共子序列。S[i-1][j-1]的含义是<以A的第i-1为结尾的字符串>与<以B的第j-1位结尾的字符串>的最长公共子序列。
buff[i][j]为S[i][j]的长度。
当
A[i] == B[j]
时
显然,由于两个字符串的最后一位相同,S[i][j]
的长度应该比S[i-1][j-1]
大1.当
A[i] != B[j]
时
结论是:buff[i][j] = max(buff[i-1][j], buff[i][j-1])
证明:
- 显然,由于添加了一个字符,
buff[i][j]
肯定大于等于buff[i-1][j]
,也肯定大于等于buff[i][j-1]
。 但是,
buff[i][j]
不能同时大于buff[i-1][j]
和buff[i][j-1]
。
反证法:
1.1. 如果buff[i][j] > buff[i-1][j]
,说明S[i][j]
的最后一位是A[i]
。(因为多了A[i]这个字符之后,最长公共子序列的长度多了1,所以多出来的这一位就是A[i]!)
1.2. 同理,如果buff[i][j] > buff[i][j-1]
,说明S[i][j]
的最后一位是B[j]
。
1.3. 那么如果buff[i][j]
同时大于buff[i-1][j]
和buff[i][j-1]
,说明S[i][j]
的最后一位既是A[i]
,也是B[j]
。那么A[i]
就与B[j]
相同了!矛盾了!所以反证出:
buff[i][j]
不能同时大于buff[i-1][j]
和buff[i][j-1]
现在,已经证明了,
buff[i][j]
肯定大于等于buff[i-1][j]
,也肯定大于等于buff[i][j-1]
,(图中绿色区域)但buff[i][j]
不能同时大于buff[i-1][j]
和buff[i][j-1]
,那buff[i][j]就只能取两者的较大者了(图中红星),这样既满足”不能同时大于两者“(只大于较小者),又满足”同时大于等于两者“,(大于较小者, 等于较大者)。
- 显然,由于添加了一个字符,
代码
class Solution {
public:
/**
* @param A, B: Two strings.
* @return: The length of longest common subsequence of A and B.
*/
int longestCommonSubsequence(string A, string B) {
// write your code here
const int lena = A.size();
const int lenb = B.size();
int buff[lena+1][lenb+1];
memset(buff, 0, sizeof(buff));
for (int i = 1; i <= lena; i++)
{
for (int j = 1; j <= lenb; j++)
{
if (A[i-1] == B[j-1])
buff[i][j] = buff[i-1][j-1] + 1;
else
buff[i][j] = max(buff[i-1][j], buff[i][j-1]);
}
}
return buff[lena][lenb];
}
};