您的位置:首页 > 产品设计 > UI/UE

lintcode longest-common-subsequence 最长公共子序列 证明

2016-07-26 09:12 288 查看

问题描述

lintcode

参考

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];
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息