每天一道LeetCode-----计算两个序列最长的公共子序列长度
来源:互联网 发布:oracle sql loader 编辑:程序博客网 时间:2024/05/29 11:08
原题链接Maximum Length of Repeated Subarray
计算两个序列最长的相同子序列的长度
简单暴力的方法是对A中每个元素遍历一遍序列B,找到相同的位置后计算从这个位置开始有多少个元素和A是相同的,唔…大概是这个样子
class Solution {public: int findLength(vector<int>& A, vector<int>& B) { int maxLen = 0; for(int i = 0; i < A.size(); ++i) { for(int j = 0; j < B.size(); ++j) { if(A[i] != B[j]) continue; int len = 0; int p = i, q = j; while(p != A.size() && q != B.size() && A[p] == B[q]) { ++p; ++q; ++len; } maxLen = std::max(maxLen, len); } } return maxLen; }};
不过超时了:(,想想也觉得没这么容易
假设序列A的长度为m,序列B的长度为n。
考虑两个序列的相同子序列
A[i, i+1, ..., i+k]
B[j, j+1, ..., j+k]
将这两个子序列分别延伸到序列末尾
A[i, i+1, ..., m-1]
B[j, j+1, ..., n-1]
那么,可以把公共子序列看成是序列A[i : m-1]和B[j : n-1]的最长公共前缀
转换成动态规划,设dp[i][j]表示A[i : m-1]和B[j : n-1]的最长公共前缀,那么
if(A[i] == B[j]) dp[i][j] = 1 + dp[i + 1][j + 1];else dp[i][j] = 0;
如果A[i] == B[j],那么A[i : m-1]和B[j : n-1]的第一个位置已经相等,只需计算A[i+1 : m-1]和B[j+1 : n-1]的最长公共前缀
如果A[i] != B[j],那么A[i : m-1]和B[j : n-1]第一个位置就不相等,显然没有公共前缀
代码如下
class Solution {public: int findLength(vector<int>& A, vector<int>& B) { vector<vector<int>> dp(A.size()+1, vector<int>(B.size()+1, 0)); int maxLen = 0; for(int i = A.size() - 1; i >= 0; --i) { for(int j = B.size() - 1; j >= 0; --j) { if(A[i] == B[j]) { /* 更新dp[i][j] */ dp[i][j] = 1 + dp[i + 1][j + 1]; maxLen = std::max(maxLen, dp[i][j]); } } } return maxLen; }};
当然了,既然是迭代法实现的动态规划,那么就能将动态规划数组降维
观察二维动态规划数组的更新情况,整个程序只用到了dp[i][j]和dp[i+1][j+1],又因为i在外层循环,所以可以改为dp[j] = dp[j+1],不过需要改变内层循环的遍历顺序
class Solution {public: int findLength(vector<int>& A, vector<int>& B) { vector<int> dp(B.size() + 1, 0); int maxLen = 0; for(int i = A.size() - 1; i >= 0; --i) { /* 遍历顺序颠倒 */ for(int j = 0; j < B.size(); ++j) { /* 相等和不相等两种情况 */ dp[j] = (A[i] == B[j]) ? 1 + dp[j + 1] : 0; maxLen = std::max(maxLen, dp[j]); } } return maxLen; }};
为了便于理解,可以
把dp[j]看成dp[i][j],表示当前的i当前的j
把dp[j+1]看成dp[i+1][j+1],表示上次循环的i和下次循环的j
假设有I1, J1, J11表示某次循环时的i,j和j+1,下一轮外层循环时i,j和j+1改为I2,J1,J11。
以下称为第一次和第二次循环
在第二次循环过程中,假设正要执行但还没有执行
dp[j] = (A[i] == B[j]) ? 1 + dp[j + 1] : 0;
写成上面符号的格式是
dp[J1] = (A[I2] == B[J1]) ? 1 + dp[J11] : 0;
因为j是从0到B.size()的,所以只有更新完dp[J1]后才会更新dp[J11],当准备更新dp[J1]时,dp[J11]还没有被更新
没有被更新的意思是dp[J11]的值在上次更新后没有被改变,上次更新时的i是I1,j是J11,所以dp[J11] == dp[I1][J11]
因为i是从A.size()到0的,所以I1 = I2 + 1,所以
dp[J11] == dp[I1][J11] == dp[I2 + 1][J11]
对于正要更新的dp[J1],此时的i是I2,所以
dp[J1] == dp[I2][J1]
所以上面的更新过程可以改为
dp[I2][J1] = (A[I2] == B[J1]) ? 1 + dp[I2 + 1][J11] : 0;
由于J11 == J1 + 1,所以
dp[I2][J1] = (A[I2] == B[J1]) ? 1 + dp[I2 + 1][J1 + 1] : 0;
形式和
dp[i][j] = (A[i] == B[j]) ? 1 + dp[i + 1][j + 1] : 0;
相同
- 每天一道LeetCode-----计算两个序列最长的公共子序列长度
- 每天一道LeetCode-----最长回文子串/序列,从头开始的最长回文子串长度
- 找两个字符串的最长公共子序列的长度
- 两个字符串的最长公共子序列的长度
- 计算两个串的最长公共子序列的长度poj1159
- 两个串最长公共子序列的长度:
- 两个序列的最长公共子序列
- 最长公共子序列的长度
- 求最长公共子序列的长度
- 最长公共子序列的长度
- 最长公共子序列长度
- 每天一道算法题--最长公共子序列和最长公共子串
- 两个字符串的最长公共子序列
- 每天一道LeetCode-----找出给定序列的所有子序列
- 求出两个序列的最长公共子序列
- 利用矩阵求两个序列的最长公共子序列
- 求两个序列的最长公共子序列
- 动态规划之,最长公共子序列,最长上升子序列,最长公共递增子序列的长度
- java基础学习day 9
- Spring集成redis缓存
- 从央视主播到投资人,外人眼中的华丽转身,张泉灵却坦言“活得像狗”
- mysql性能优化
- 总结js常用函数和常用技巧(持续更新)
- 每天一道LeetCode-----计算两个序列最长的公共子序列长度
- 遍历list集合的方式
- Problem5:Longest Palindromic Substring
- linux CRONTAB定时任务
- Maven下载及配置本地仓库
- AppBarLayout 禁止滑动
- 关于枚举类型的学习(enum)
- QT控件大全 三十三 QRoundProgressBar
- 魏杰教授《解读十九大:迎接新时代,抓住新机遇》-转