最长回文子序列LCS,最长递增子序列LIS及相互联系
最长公共子序列LCS
Lintcode 77. 最长公共子序列
LCS问题是求两个字符串的最长公共子序列
\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长度
不求长度求原序列
参考
- LIS算法: 最长上升子序列
- 算法竞赛入门经典-例题27:王子与公主
- 算法导论第三版思考题15-2
最长回文子序列LCS,最长递增子序列LIS及相互联系的更多相关文章
- hdu 3068 最长回文(manachar求最长回文子串)
题目连接:hdu 3068 最长回文 解题思路:通过manachar算法求最长回文子串,如果用遍历的话绝对超时. #include <stdio.h> #include <strin ...
- hdu 3068 最长回文(manacher&最长回文子串)
最长回文 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- 51NOD 1088 最长回文子串&1089 最长回文子串 V2(Manacher算法)
回文串是指aba.abba.cccbccc.aaaa这种左右对称的字符串. 输入一个字符串Str,输出Str里最长回文子串的长度. Input 输入Str(Str的长度 <= 1000(第二题要 ...
- HDU 3068 最长回文 (Manacher最长回文串)
Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.回文就是正反读都是一样的字符串,如aba, abba等 Input 输 ...
- 最长回文子序列/最长回文子串(DP,马拉车)
字符子串和字符子序列的区别 字符字串指的是字符串中连续的n个字符:如palindrome中,pa,alind,drome等都属于它的字串 而字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符: ...
- LeetCode-求最长回文子序列
题目:给定一个字符串,求它的最长回文子串 /*求最长回文子串,以当前字符为中心,向两边同时拓展*/ string longestPalindrome(string s) { int len = s.l ...
- leetcode-5 最长回文子串(动态规划)
题目要求: * 给定字符串,求解最长回文子串 * 字符串最长为1000 * 存在独一无二的最长回文字符串 求解思路: * 回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文 ...
- Manacher算法:求解最长回文字符串,时间复杂度为O(N)
原文转载自:http://blog.csdn.net/yzl_rex/article/details/7908259 回文串定义:"回文串"是一个正读和反读都一样的字符串,比如&q ...
- 使用manacher算法解决最长回文子串问题
要解决的问题 求一个字符串最长回文子串是什么.且时间复杂度 O(N) 具体描述可参考: LeetCode_5_最长回文子串 LintCode_200_最长回文子串 暴力解法 以每个字符为中心向左右两边 ...
- 删除部分字符使其变成回文串问题——最长公共子序列(LCS)问题
先要搞明白:最长公共子串和最长公共子序列的区别. 最长公共子串(Longest Common Substirng):连续 最长公共子序列(Longest Common Subsequence,L ...
随机推荐
- Class文件内容解析
一.概述 任何一个Class文件都对应唯一一个类或接口的定义信息,但是不是所有的类或接口都得定义在文件中(它们也可以通过类加载器直接生成). Class文件是一组以8位字节为基础单位的二进制流,各个数 ...
- Python基础知识(程序结构)
流程控制语句 选择语句.条件表达式.循环语句.跳转语句.pass空语句 程序结构三种基本结构 顺序结构.选择结构.循环结构 顺序结构 按照代码顺序依次运行 选择结构 根据条件表达式结果选择执行不同的语 ...
- OpenCV-Python画直方图和累积直方图
代码如下: import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread('C:\\Users\\adm ...
- 【VS开发】设备控制台 (DevCon.exe) 示例
设备控制台 (DevCon.exe) 示例 本部分提供以下设备控制台 (DevCon.exe) 命令的示例: DevCon HwIDs 示例 1:查找所有硬件 ID 示例 2:使用模式查找硬件 ID ...
- dll的封装和使用
背景 在windows平台下,要实现函数的封装,一般采用的是dll动态库的形式 实现了函数的封装就意味着实现过程的隐藏 可以实现跨平台和跨语言的使用 实施步骤 生成dll动态库 在VS中生成新项目,应 ...
- 网站性能优化(website performance optimization)2
我们先研究下构建渲染树前的几个步骤:也就是DOM和CSSOM,通常这些步骤的效果最差使你的网页呈现速度非常慢,我们是讨论尽可能快的将HTML流式传输给客户端,使浏览器能够开始构建DOM,还有其他注意事 ...
- json字段为null时输出空字符串
Map < String , Object > jsonMap = new HashMap< String , Object>(); jsonMap.put(); jsonMa ...
- git与码云关联教程
注:我用的这种方法是利用“公钥”使本地仓库与码云建立起联系,从而不需要用户名与密码的方法. 1.首先,创建好码云,再在码云上创建好个人仓库,然后复制好仓库地址,这里的地址是指“SSH”类型的. 2.下 ...
- 【经典问题】maximum subset sum of vectors
AtCoder Beginner Contest 139 Task F Engines 题目大意 给定 $n$ 个二维向量,从中选出若干个,使得它们的和的模最大. 分析 这是一个经典问题,还有一种提法 ...
- Spring Boot 五种热部署方式,极速开发就是生产力!
1.模板热部署 在 Spring Boot 中,模板引擎的页面默认是开启缓存的,如果修改了页面的内容,则刷新页面是得不到修改后的页面的,因此我们可以在application.properties中关闭 ...