1143.最长公共子序列
看完题后的思路
dp[i][j] A[0-i] B[0-j] 的最长公共子序列
dp[i][j] =
(1) A[i]=B[j] dp[i-1][j-1]+1
(2) 假如最长序列包含A[i] 找到B[p]=A[i] dp[i-1][p-1]+1 从右向左找第一个p就行,因为越长,包含的公共长度越长
(3) 假如最长子序列包含B[j] 同上 = dp[q-1][j-1] +1
(4) 假设即不包含 A[i] 也不包含 B[j] =dp[i-1][j-1]
初始化
dp[i][0]= 0/1
dp[0][j]=0/1
代码
// 1143.最长公共子序列
public int longestCommonSubsequence(String text1, String text2) {
char[] nums1 = text1.toCharArray();
char[] nums2 = text2.toCharArray();
int m=nums1.length,n=nums2.length;
int[][] dp=new int[m][n];
// 初始化
for (int i = 0; i <n ; i++) {
if (nums1[0]==nums2[i]){
dp[0][i]=1;
for (int j = i+1; j <n ; j++) {
dp[0][j]=1;
}
break;
}else {
dp[0][i]=0;
}
}
for (int i = 0; i <m ; i++) {
if (nums2[0]==nums1[i]){
dp[i][0]=1;
for (int j = i+1; j <m ; j++) {
dp[j][0]=1;
}
break;
}else {
dp[i][0]=0;
}
}
// 核心
for (int i = 1; i <m ; i++) {
for (int j = 1; j <n ; j++) {
if (nums1[i]==nums2[j]){
dp[i][j]=dp[i-1][j-1]+1;
}else {
dp[i][j]=dp[i-1][j-1];
for (int k = i; k >=0 ; k--) { // 假设包含 B[j]
if (nums1[k]==nums2[j]){
if (k==0){
dp[i][j]=Math.max(dp[i][j],1);
}else {
dp[i][j]=Math.max(dp[i][j],dp[k-1][j-1]+1);
}
break;
}
}
for (int k = j; k >=0; k--) { // 假设包含 A[i]
if (nums1[i]==nums2[k]){
if (k==0){
dp[i][j]=Math.max(dp[i][j],1);
}else {
dp[i][j]=Math.max(dp[i][j],dp[i-1][k-1]+1);
}
break;
}
}
}
}
}
return dp[m-1][n-1];
}
复杂度
看完题解后的收货
dp[i][j] A[0-i] B[0-j] 的最长公共子序列
dp[i][j] =
(1) A[i]=B[j] dp[i-1][j-1]+1
(2) 当 A[i]!=B[j]
dp[i][j] = max(dp[i-1][j],dp[i][j-1]) 用稍微短一点的去推
初始化
int[][] dp=new int[m][n];
// 初始化
for (int i = 0; i <n ; i++) {
if (nums1[0]==nums2[i]){
dp[0][i]=1;
for (int j = i+1; j <n ; j++) {
dp[0][j]=1;
}
break;
}else {
dp[0][i]=0;
}
}
for (int i = 0; i <m ; i++) {
if (nums2[0]==nums1[i]){
dp[i][0]=1;
for (int j = i+1; j <m ; j++) {
dp[j][0]=1;
}
break;
}else {
dp[i][0]=0;
}
}
1035.不相交的线
看完题后的思路
本题的本质是求两个数组的最长公共子序列
代码
public int maxUncrossedLines(int[] nums1, int[] nums2) {
int m=nums1.length,n=nums2.length;
int[][] dp=new int[m][n];
// 初始化
for (int i = 0; i <n ; i++) {
if (nums1[0]==nums2[i]){
dp[0][i]=1;
for (int j = i+1; j <n ; j++) {
dp[0][j]=1;
}
break;
}else {
dp[0][i]=0;
}
}
for (int i = 0; i <m ; i++) {
if (nums2[0]==nums1[i]){
dp[i][0]=1;
for (int j = i+1; j <m ; j++) {
dp[j][0]=1;
}
break;
}else {
dp[i][0]=0;
}
}
// 核心
for (int i = 1; i <m ; i++) {
for (int j = 1; j < n; j++) {
if (nums1[i]==nums2[j]){
dp[i][j]=dp[i-1][j-1]+1;
}else {
dp[i][j]=Math.max(dp[i-1][j],dp[j-1][i]);
}
}
}
return dp[m-1][n-1];
}
53. 最大子序和
法一 贪心算法
法二 动态规划
dp[i] 以 nums[i]结尾的[0,i]的最大子序和
dp[i]=max(dp[i-1]+num[i],nums[i])
初始化
dp[0]=nums[0]
代码
public int maxSubArray(int[] nums) {
int dp[]=new int[nums.length];
dp[0]=nums[0];
int max=dp[0];
for (int i = 1; i <nums.length ; i++) {
dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);
max=Math.max(dp[i],max);
}
return max;
}