最长递增子序列AC
最长公共子序列AC
最长公共子串AC
最小编辑代价AC
最长公共子序列和最长公共子串的区别
1.递推公式求解dp
子序列:
s1[i-1]==s2[j-1] dp[i][j]=dp[i-1][j-1]+1
s1[i-1]!=s2[j-1] dp[i][j]=max(dp[i-1][j], dp[i][j-1])
子串:
s1[i-1]==s2[j-1] dp[i][j]=dp[i-1][j-1]+1
s1[i-1]!=s2[j-1] dp[i][j]=0
2.返回结果
子序列:之间返回矩阵右下角的值
子串:需要遍历矩阵寻找最大值
最长递增子序列AC
package dp;
/**
最长递增子序列(LIS)
题目描述:
给定数组arr,返回arr的最长递增子序列。
比如arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为[1,3,4,8,9],这个子序列的长度5。
*/
//时间复杂度O(n^2)
//nowcoder pass
public class AscentSequence {
public int findLongest(int[] arr, int n) {
int[] dp = new int[n];
int maxLen = 1;
for (int i = 0; i < n; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (arr[j] < arr[i] && dp[i] < dp[j]+1) {
dp[i] = dp[j]+1;
maxLen = Math.max(maxLen, dp[i]);
}
}
}
return maxLen;
}
}
最长公共子序列AC
要注意与最长公共子串的递归公式的区别
s1[i-1]==s2[j-1] dp[i][j]=dp[i-1][j-1]+1
s1[i-1]!=s2[j-1] dp[i][j]=max(dp[i-1][j], dp[i][j-1])
package dp;
/**
最长公共子序列
题目描述
对于两个字符串,请设计一个高效算法,求他们的最长公共子序列的长度.
测试样例:
"1A2C3D4B56",10,"B1D23CA45B6A",12
返回:6
思路:经典的动态规划问题
str1长度为m,str2长度为n
dp[m+1][n+1]
dp[i][j]表示str1[0...i-1]与str2[0...j-1]的最长公共子序列的长度
递推公式:
str1[i-1]==str2[j-1] dp[i][j]=dp[i-1][j-1]+1
str1[i-1]!=str2[j-1] dp[i][j]=max(dp[i-1][j], dp[i][j-1])
多出来的一行和一列是第 0 行和第 0 列,
初始化为 0,表示空字符串和另一字符串的子串的最长公共子序列
str1="app",str2="apple",dp[0][3]表示 “” 和 “app” 的最长公共字串。
*/
//nowcoder pass
public class LCSubsequence {
public int findLCS(String str1, int m, String str2, int n) {
if (str1 == null || str2 == null) {
return 0;
}
int[][] dp = new int[m+1][n+1];
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1[i-1] == s2[j-1]) {
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];
}
}
最长公共子串AC
要注意与最长公共子序列的递归公式的区别
s1[i-1]==s2[j-1] dp[i][j]=dp[i-1][j-1]+1
s1[i-1]!=s2[j-1] dp[i][j]=0
package dp;
/**
最长公共子串
题目描述:
对于两个字符串,请设计一个时间复杂度为O(m*n)的算法(这里的m和n为两串的长度),
求出两串的最长公共子串的长度。这里的最长公共子串的定义为两个序列U1,U2,..Un和V1,V2,...Vn,
其中Ui + 1 == Ui+1,Vi + 1 == Vi+1,同时Ui == Vi。
给定两个字符串A和B,同时给定两串的长度n和m。
测试样例:
"1AB2345CD",9,"12345EF",7
返回:4
思路:动态规划问题
s1长度为m,s2长度为n
dp[m+1][n+1]
递推公式:
s1[i-1]==s2[j-1] dp[i][j]=dp[i-1][j-1]+1
s1[i-1]!=s2[j-1] dp[i][j]=0
*/
//nowcoder pass
public class LCSubstring {
public int findLongest(String str1, int m, String str2, int n) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
int[][] dp = new int[m+1][n+1];
int maxLen = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1[i-1] == s2[j-1]) {
dp[i][j] = dp[i-1][j-1]+1;
maxLen = Math.max(maxLen, dp[i][j]);
} else {
dp[i][j] = 0;//求dp时,和最长公共子序列仅这一行的区别
}
}
}
return maxLen;
}
}
最小编辑代价AC
package dp;
/**
最小编辑代价
题目描述:
对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串,
定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法,求出将A串变为B串所需要的最少代价。
给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。
保证两串长度均小于等于300,且三种代价值均小于等于100。
测试样例:
"abc",3,"adc",3,5,3,100
返回:8
思路:动态规划
*/
//nowcoder pass
public class MinEditCost {
public int findMinCost(String str1, int m, String str2, int n, int ic, int dc, int rc) {
char[] s1 = str1.toCharArray();
char[] s2 = str2.toCharArray();
int[][] dp = new int[m+1][n+1];
//第一行
for (int i = 0; i <= n; i++) {
dp[0][i] = i*ic;
}
//第一列
for (int i = 0; i <= m; i++) {
dp[i][0] = i*dc;
}
for (int i = 1; i <= m; i++) {
for(int j = 1; j <= n; j++) {
if (s1[i-1] == s2[j-1]) {
dp[i][j] = dp[i-1][j-1];
} else {
dp[i][j] = dp[i-1][j-1] + rc;
}
dp[i][j] = Math.min(dp[i][j], dp[i-1][j]+dc);
dp[i][j] = Math.min(dp[i][j], dp[i][j-1]+ic);
}
}
return dp[m][n];
}
}