题目描述
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
示例 1:
输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace”,它的长度为 3
提示:
1 <= text1.length <= 1000
1 <= text2.length <= 1000
输入的字符串只含有小写英文字符。
来源:LeetCode
解法一
动态规划思想的本质是动态表格(dynamic table),使用动态规划必须满足两个条件:1.重复子问题,2.最优子结构,表格的思想是以空间换时间,把求解的所有子问题的解都保存下来,不用重复计算,最优子结构则保证了,原问题的解由子问题的组合构成,就可以写成递推公式,在较短的时间复杂度内求解。
针对LCS问题,把字符串a表示为(X1,X2,…,Xm),字符串b表示为(Y1,Y2,…,Yn),我们先看看能不能划分子问题:求a和b的LCS,可以定义为LCS[i,j],其中i表示从X1到Xi的子串,j表示从Y1到Yj的子串,这里固定了字符串的起始索引1。为什么这么划分子问题?因为如果起始索引和结束索引都动态的话,那就更难解决了,更重要的是,我们求最长公共子序列,起始索引动态是没有意义的,因为起始索引大于1的子问题,其结果总会小于等于索引为1的子问题结果。
问题形式化之后,我们发现,如果Xi=Yj,则LCS[i,j]=LCS[i-1,j-1]+1,只需要再考虑LCS[i-1,j-1]这个子问题,如果不相等,则有两个子问题需要解决,LCS[i,j]=max(LCS[i,j-1], LCS[i-1,j]),如果i=0或j=0,说明有一个字符串已经结束了,则LCS[i,j]=0
解决递推公式问题,有两种方法,一种是自底向上,从求解小问题开始,逐渐求解整个问题,另一种是递归的方式,因为中途有很多重复子问题(如LCS[i-1,j-1]可能是LCS[i,j]的子问题,也可能LCS[i,j-1]的子问题),所以使用memo数组记录下这些子问题的解。
以下是递归+memo的解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public: int longestCommonSubsequence(string text1, string text2) { int size1 = text1.size(); int size2 = text2.size(); int memo[1001][1001]; for(int i = 0; i < 1001; i++) { for(int j = 0; j < 1001; j++) { memo[i][j] = -1; } } return lcs(text1, text2, memo, size1-1, size2-1); } int lcs(string & a, string & b, int memo[][1001], int i, int j) { if(i == -1 || j == -1) return 0; if(memo[i][j] != -1) return memo[i][j]; if(a[i] == b[j]) { memo[i][j] = lcs(a, b, memo, i-1, j-1) + 1; return memo[i][j]; } else { memo[i][j] = max(lcs(a, b, memo, i-1, j), lcs(a, b, memo, i, j-1)); return memo[i][j]; } } };
|
解法二
自底向上的解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public: int longestCommonSubsequence(string text1, string text2) { int dp[1001][1001]; memset(dp, 0, 1001*1001*sizeof(int)); int size1 = text1.size(); int size2 = text2.size(); for(int i = 1; i <= size1; i++) { for(int j = 1; j <= size2; j++) { if(text1[i-1] == text2[j-1]) { dp[i][j] = dp[i-1][j-1] + 1; } else { dp[i][j] = max(dp[i][j-1], dp[i-1][j]); } } } return dp[size1][size2]; } };
|