最长回文子序列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 ...
随机推荐
- Ajax操作的四个步骤
Ajax操作的四个步骤: 创建Ajax对象 连接服务器 发送请求 接收返回信息 <!DOCTYPE html> <html> <head lang="en&qu ...
- WIN10远程协助无法控制的解决方法
这个问题比较常见小编整理的解决方法如下: 方法一:用QQ远程协助对方电脑,需要QQ告诉对方右键单击计算机(这台电脑)点管理打开计算机管理界面选择本地用户和组,再选择用户,右侧会出现所有的本地用户,包括 ...
- NXP-PN511-antenna-design-quide
NXP-PN511-antenna-design-quide 文库有下载 C1 C2
- 【Linux-驱动】RTC设备驱动架构
在Linux操作系统中,RTC设备驱动的架构如下图所示: RTC设备驱动涉及的文件:class.c.rtc-dev.c : 建立/dev/rtc0设备,同时注册相应的操作函数.interface.c ...
- 分层最短路(牛客第四场)-- free
题意: 给你边权,起点和终点,有k次机会把某条路变为0,问你最短路是多长. 思路: 分层最短路模板题.题目有点坑(卡掉了SPFA,只能用dijkstra跑的算法). #include<iostr ...
- Laravel-admin form 表单是增加或者修改
Laravel-admin 实现 form 表单是增加或者修改的三种方法,应用情景:1.新增或者修改 form 展示的表单不同:2.新增或者保存前后回调进行其他的操作 1. use Illuminat ...
- VMware 无法开机
无法打开磁盘 虚拟机无法打开磁盘 "或者某一个快照所依赖的磁盘 原因:未能锁定文件"的解决办法 很多人在使用虚拟机是都会遇到“无法打开磁盘" x:\*\*vmdk &qu ...
- Redis安全策略
1. 开启redis密码认证,并设置高复杂度密码 描述 redis在redis.conf配置文件中,设置配置项requirepass, 开户密码认证. redis因查询效率高,auth这种命令每秒能处 ...
- springboot拦截中自动注入的组件为null问题解决方法
一.写SpringUtil类来获取Springh管理的类实例,判断是否注入成功,如果没有注入成功重新获取注入 package com.util; import org.springframework. ...
- ionic 提示 Error: Could not find gradle wrapper within Android SDK.
Error: Could not find gradle wrapper within Android SDK. Might need to update your Android SDK. 到And ...