最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
解:
设置子序列的问题==》十有八九是动态规划
明确dp数组
dp[i][j]表示text1的前i个元素和text2的前j个元素的最长公共子序列长度
找dp数组的表示–状态转移方程
//将dp[i][j]表示出来
//若text1[i]==text2[j],dp[i][j]=dp[i-1][j-1]+1
//不等于dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
base case
dp[0][.]和dp[.][0]均是0
搞定!
//递归解法,由上而下:
public int longestCommonSubsequence(String text1, String text2) {
int m=text1.length()-1;
int n=text2.length()-1;
char[] tt1=text1.toCharArray();
char[] tt2=text2.toCharArray();
return dp(m,n,tt1,tt2);
}
int dp(int i,int j,char[] tt1,char[] tt2){
if(i==-1||j==-1)return 0;
if(tt1[i]==tt2[j]){
return dp(i-1,j-1,tt1,tt2)+1;
}else{
return Math.max(dp(i-1,j,tt1,tt2),dp(i,j-1,tt1,tt2));
}
}
用dp数组优化-
//由底向上
public int longestCommonSubsequence(String text1, String text2) {
// 字符串转为char数组以加快访问速度
char[] str1 = text1.toCharArray();
char[] str2 = text2.toCharArray();
int m = str1.length, n = str2.length;
// 构建dp table,初始值默认为0
int[][] dp = new int[m + 1][n + 1];
// 状态转移
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (str1[i - 1] == str2[j - 1])
// 找到LCS中的字符
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
return dp[m][n];
}
最长自增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
解:
1.首先,要去定义dp数组,明确dp数组的含义。本题中,dp[i]表示以nums[i]结尾的最长递增子序列的长度。
2.假设dp[0]…dp[i-1]已知,怎么表示dp[i]?
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
3.将dp[0]…dp[i]都表示出来。
for(int i=0;i<nums.length();i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i]=Math,max(dp[i],dp[j]+1);
}
}
}
4.base case就是dp[i]均是1.
public int lengthOfLIS(int[] nums) {
//dp[i]表示以num[i]结尾的递增组序列的长度
int[] dp=new int[nums.length];
for(int i=0;i<dp.length;i++){
dp[i]=1;
}
for(int i=0;i<nums.length;i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i]=Math.max(dp[j]+1,dp[i]);
}
}
}
int res=0;
for(int i=0;i<dp.length;i++){
res=Math.max(dp[i],res);
}
return res;
}
最长回文子序列
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
解:
class Solution {
public int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] f = new int[n][n];
for(int i=0;i<n;i++){
f[i][i]=1;
}
for (int i = n-1; i>=0 ; i--) {
for (int j = i + 1; j < n; j++) {
if (s.charAt(i) == s.charAt(j)) {
f[i][j] = f[i + 1][j - 1] + 2;
} else {
f[i][j] = Math.max(f[i + 1][j], f[i][j - 1]);
}
}
}
return f[0][n - 1];
}
}