一、题目
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。
二、解法
思路:动态规划,此题思路在之前的 leetcode 718. 最长重复子数组。
-
hello,ahslo,结果是hlo,答案是3(因为子序列不必是连续的)
-
res(i,j)表示字符串a的前i个字符和字符串b的前j个字符的结果,最终求解的是res(5,5)
-
首先列出状态转移方程:
-
r e s ( i , j ) = { 0 , i = 0 o r j = 0 r e s ( i − 1 , j − 1 ) + 1 , A i = B j max ( r e s ( i − 1 , j ) , r e s ( i , j − 1 ) ) , A i ≠ B j res(i,j)=\left\{ \begin{aligned} 0 &,&i=0 &&or && j=0\\ res(i-1,j-1)+1 &,& A_i=B_j \\ \max(res(i-1,j),res(i,j-1)) &,& A_i\neq B_j \end{aligned} \right. res(i,j)=⎩⎪⎨⎪⎧0res(i−1,j−1)+1max(res(i−1,j),res(i,j−1)),,,i=0Ai=BjAi=Bjorj=0
0 | h | e | l | l | o | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
a | 0 | 0 | 0 | 0 | 0 | 0 |
h | 0 | 1 | 1 | 1 | 1 | 1 |
s | 0 | 1 | 1 | 1 | 1 | 1 |
l | 0 | 1 | 1 | 2 | 2 | 2 |
o | 0 | 1 | 1 | 2 | 2 | 3 |
- 根据dp数组,可以回溯得到最长公共子序列是"hlo"
- 由于dp数组太占空间,可用两个一维数组prev和cur来减少空间复杂度
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m=text1.length(),n=text2.length();
vector<int> prev(n+1,0),cur(n+1,0);
for(int i=1;i<=m;++i){
for(int j=1;j<=n;++j){
if(text1[i-1]==text2[j-1]){
cur[j]=prev[j-1]+1;
}else{
cur[j]=max(prev[j],cur[j-1]);
}
}
prev=cur;
}
return cur[n];
}
};