最长公共子序列LCS

Lintcode 77. 最长公共子序列

LCS问题是求两个字符串的最长公共子序列

\[ dp[i][j] =
\left\{\begin{matrix}
& max(dp[i-1][j], dp[i][j-1]), s[i] != s[j]\\
& dp[i-1][j-1] + 1, s[i] == s[j]
\end{matrix}\right.
\]

许多问题可以变形为LCS问题以求解

class Solution {
public:
/**
* @param A: A string
* @param B: A string
* @return: The length of longest common subsequence of A and B
*/
int longestCommonSubsequence(string &A, string &B) {
// write your code here
int n = A.size();
int m = B.size();
std::vector<vector<int>> dp(m+1, vector<int>(n+1, 0)) ;
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){ if(A[i-1] == B[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]); }
} return dp[m][n];
}
};

因为dp[i][j]仅仅用到了i-1和i层的数据,因此可以用滚动数组来压缩空间,使得空间复杂度为\(O(min(m,n))\)

class Solution {
public:
/**
* @param A: A string
* @param B: A string
* @return: The length of longest common subsequence of A and B
*/
int longestCommonSubsequence(string &A, string &B) {
// write your code here
int n = A.size();
int m = B.size();
std::vector<vector<int>> dp(2, vector<int>(n+1, 0)) ;
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){ if(A[i-1] == B[j-1]) dp[i%2][j] = dp[(i-1)%2][j-1] + 1;
else dp[i%2][j] = max(dp[(i-1)%2][j], dp[i%2][j-1]); }
} return dp[m%2][n];
}
};

最长递增子序列LIS

300. Longest Increasing Subsequence

动态规划

可以假定dp[i]为以nums[i]结尾的LIS长度,则dp[i] = max(dp[j] + 1)( j<i 且 nums[j] < nums[i]), 时间复杂度为\(O(n^2)\),时间复杂度为\(O(n)\)

class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1);
int MAX = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){
if(nums[i] > nums[j]) dp[i] = max(dp[j] + 1, dp[i]);
}
MAX = max(MAX, dp[i]);
} return MAX;
}
};

贪心+二分

首先我们设置一个辅助数组v,其中v[i]表示长度为i-1的LIS的末尾值,首先扫描原数组,当处理到nums[i]时和v中的数据比较,二分查找最后一个比nums[i]小的值,并更换,如果不存在,则加入到末尾,v最后的长度就是原数组LIS的长度,时间复杂度\(nlgn\)

class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> v; for(int i = 0; i < n; ++i){
auto loc = lower_bound(v.begin(), v.end(), nums[i]);
if(loc == v.end()) v.push_back(nums[i]);
else *loc = nums[i];
} return v.size();
}
};

如果仅仅是求LIS长度和允许改变原数组,空间复杂度可降低为\(O(1)\)

class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
auto p = nums.begin();
auto q = nums.begin(); for(int i = 0; i < n; i++){
auto r = lower_bound(p, q, nums[i]);
if(r == q){ ++q; }
*r = nums[i];
} return q - p;
}
};

LIS与LCS的相互转化

LIS问题可以变形为LCS问题,如输入数组为[5,1,4,2,3],最长递增子序列为[1,2,3],可以先将原数组排序得到一个新数组[1,2,3,4,5],然后新数组与原数组作为LCS的输入求解, 时间复杂度为\(O(n^2)\), 空间复杂度为\(O(n^2)\)

LCS问题也可变为LIS问题,假定输入数组为数字数组如A=[1,7,5,4,8,3,9], B=[1,4,3,5,6,2,8,9],且在A,B两个序列中每个元素各不相同(如1-n的排列),如果使用LCS求解最长公共子序列长度,则复杂度为\(O(n^2)\),A,B两个序列中每个元素各不相同,因此我们可以将A重新编码A=[1,2,3,4,5,6,7](编码不重复), B可以编码为B=[1,4,6,3,0,0,5,7](0表示不存在,也可以直接删除),然后求重新编码后A,B的LIS长度,时间复杂度为\(O(nlgn)\)

LCS与最长回文子序列LPS及变种

求S的最长回文子序列也可以使用LCS的思想,先将S反转得到S',然后求LCS(S,S')

leetcode 516. Longest Palindromic Subsequence

class Solution {
public:
int lcs(string &A, string &B) {
int n = A.size();
int m = B.size();
std::vector<vector<int>> dp(m+1, vector<int>(n+1, 0)) ;
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){ if(A[i-1] == B[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]); }
} return dp[m][n];
}
int longestPalindromeSubseq(string s) {
string t(s.rbegin(), s.rend());
return lcs(s, t);
}
};

变种:求在S中任何位置插入或删除最少字符个数使得S成为回文串

解法:先求最长回文子序列,然后用原长度-LPS长度

不求长度求原序列

参考

最长回文子序列LCS,最长递增子序列LIS及相互联系的更多相关文章

  1. hdu 3068 最长回文(manachar求最长回文子串)

    题目连接:hdu 3068 最长回文 解题思路:通过manachar算法求最长回文子串,如果用遍历的话绝对超时. #include <stdio.h> #include <strin ...

  2. hdu 3068 最长回文(manacher&amp;最长回文子串)

    最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  3. 51NOD 1088 最长回文子串&1089 最长回文子串 V2(Manacher算法)

    回文串是指aba.abba.cccbccc.aaaa这种左右对称的字符串. 输入一个字符串Str,输出Str里最长回文子串的长度. Input 输入Str(Str的长度 <= 1000(第二题要 ...

  4. HDU 3068 最长回文 (Manacher最长回文串)

    Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.回文就是正反读都是一样的字符串,如aba, abba等   Input 输 ...

  5. 最长回文子序列/最长回文子串(DP,马拉车)

    字符子串和字符子序列的区别 字符字串指的是字符串中连续的n个字符:如palindrome中,pa,alind,drome等都属于它的字串 而字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符: ...

  6. LeetCode-求最长回文子序列

    题目:给定一个字符串,求它的最长回文子串 /*求最长回文子串,以当前字符为中心,向两边同时拓展*/ string longestPalindrome(string s) { int len = s.l ...

  7. leetcode-5 最长回文子串(动态规划)

    题目要求: * 给定字符串,求解最长回文子串 * 字符串最长为1000 * 存在独一无二的最长回文字符串 求解思路: * 回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文 ...

  8. Manacher算法:求解最长回文字符串,时间复杂度为O(N)

    原文转载自:http://blog.csdn.net/yzl_rex/article/details/7908259 回文串定义:"回文串"是一个正读和反读都一样的字符串,比如&q ...

  9. 使用manacher算法解决最长回文子串问题

    要解决的问题 求一个字符串最长回文子串是什么.且时间复杂度 O(N) 具体描述可参考: LeetCode_5_最长回文子串 LintCode_200_最长回文子串 暴力解法 以每个字符为中心向左右两边 ...

  10. 删除部分字符使其变成回文串问题——最长公共子序列(LCS)问题

    先要搞明白:最长公共子串和最长公共子序列的区别.    最长公共子串(Longest Common Substirng):连续 最长公共子序列(Longest Common Subsequence,L ...

随机推荐

  1. springMVC入门配置案例

    1.spring的jar包下载 进入http://repo.springsource.org/libs-release-local/,然后依次点击org/-->springframework-- ...

  2. PHP进阶之路 -- 02 面向对象

    PHP进阶之路-- 之 “面向对象” 基础 概念 类的介绍和定义 类的属性 类常量 类的自动加载 构造函数和析构函数 访问控制 对象继承 范围解析操作符 static静态关键字 抽象类 对象接口 Tr ...

  3. C++类中的一些细节(重载、重写、覆盖、隐藏,构造函数、析构函数、拷贝构造函数、赋值函数在继承时的一些问题)

    1 函数的重载.重写(重定义).函数覆盖及隐藏 其实函数重载与函数重写.函数覆盖和函数隐藏不是一个层面上的概念.前者是同一个类内,或者同一个函数作用域内,同名不同参数列表的函数之间的关系.而后三者是基 ...

  4. PJzhang:python基础入门的7个疗程-six

    猫宁!!! 参考链接:易灵微课-21天轻松掌握零基础python入门必修课 https://www.liaoxuefeng.com/wiki/1016959663602400 第16天:开源模块 sy ...

  5. PJzhang:从csdn到pipal密码分析工具

    猫宁!!! 偶然看到一篇短文,是对2011年csdn泄露的约643万数据的数据汇总分析,这里做个简要总结 .   一.单一密码使用5000人以上的,14个,当时密码中有两个命名方式很有趣,dearbo ...

  6. delete an extra edge from BST

    Given a BST, remove an extra edge to make it BST. 7 / \ 5   9 /  \ / 3    8 public void deleteEdge(T ...

  7. [转帖]Oracle 数据库官方不支持VMWare

    Oracle 数据库官方不支持VMWare [日期:2014-05-13] 来源:Linux社区  作者:myhuaer [字体:大 中 小]   https://www.linuxidc.com/L ...

  8. CF949E Binary Cards 题解

    题面 首先发现:一个数最多会出现1次: 然后深入推出:一个数不会既用它又用它的相反数: 这样就可以依次考虑每一位了: 如果所有的数都不含有这一位,那么就直接把所有的数除以2 如果含有,那么就减去这一位 ...

  9. 洛谷 P1268 树的重量 题解

    题面 目的:求出树的各边长度 条件:每个节点之间最短路.整个图中不存在负边 我们可以每一次把一个点加入树内,求出这个点和已经构建好的树的边的长度: 这个长度抽象理解一下就是(dis[i][j]+dis ...

  10. 【GDOI】2018题目及题解(未写完)

    我的游记:https://www.cnblogs.com/huangzihaoal/p/11154228.html DAY1 题目 T1 农场 [题目描述] [输入] 第一行,一个整数n. 第二行,n ...