leecode更新

This commit is contained in:
markilue 2022-12-18 12:29:57 +08:00
parent 600003ba7f
commit 29fe083026
2 changed files with 225 additions and 0 deletions

View File

@ -0,0 +1,110 @@
package com.markilue.leecode.dynamic;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic
*@Author: dingjiawen
*@CreateTime: 2022-12-18 10:05
*@Description:
* TODO 力扣1035题 不相交的线:
* 在两条独立的水平线上按给定的顺序写下 nums1 nums2 中的整数
* 现在可以绘制一些连接两个数字 nums1[i] nums2[j] 的直线这些直线需要同时满足满足
* nums1[i] == nums2[j]
* 且绘制的直线不与任何其他连线非水平线相交
* 请注意连线即使在端点也不能相交每个数字只能属于一条连线
* 以这种方法绘制线条并返回可以绘制的最大连线数
*@Version: 1.0
*/
public class T31_MaxUncrossedLines {
@Test
public void test(){
int[] nums1 = {2, 5, 1, 2, 5};
int[] nums2 = {10, 5, 2, 1, 5, 2};
System.out.println(maxUncrossedLines1(nums1,nums2));
}
/**
* 思路本质上还是想让两个数相等但是对两个相等的数有要求,本质上好像就是子序列问题因为子序列可删可不删
* TODO 动态规划法
* (1)dp定义: dp[i][j]表示使用nums1[0-i]和nums2[0-j]的最大连线数
* (2)dp状态转移方程:if nums1[i-1]==nums2[j-1] 则dp[i][j]=dp[i-1][j-1]+1
* else dp[i][j]=max(dp[i][j-1],dp[i-1][j])
* 这里使用nums1[i-1]==nums2[j-1]主要是为了初始化方便
* (3)dp初始化:dp[0][i]=0 dp[i][0]=0;
* (4)dp遍历顺序:两个for可以任意调换
* (5)dp举例推导 以nums1 = [2,5,1,2,5], nums2 = [10,5,2,1,5,2]为例
* [n 10 5 2 1 5 2]
* n 0 0 0 0 0 0 0
* 2: 0 0 0 1 1 1 1
* 5: 0 0 1 1 1 2 2
* 1: 0 0 1 1 2 2 2
* 2: 0 0 1 2 2 2 3
* 5: 0 0 1 2 2 3 3
* 速度击败99.45%内存击败34.1%
* @param nums1
* @param nums2
* @return
*/
public int maxUncrossedLines(int[] nums1, int[] nums2) {
if(nums1.length<nums2.length){
return maxUncrossedLines(nums2,nums1);
}
int[][] dp = new int[nums1.length + 1][nums2.length + 1];
for (int i = 1; i < dp.length; i++) {
for (int j = 1; j < dp[0].length; j++) {
if(nums1[i-1]==nums2[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[nums1.length][nums2.length];
}
/**
* 官方最快题解本质上是一个一维数组优化dp
* 速度击败100% 内存击败97.81%
* 2ms
* @param nums1
* @param nums2
* @return
*/
public int maxUncrossedLines1(int[] nums1, int[] nums2) {
int[] dp = new int[nums2.length];
int rs = 0;
for (int j = 0; j < nums2.length; j++) {
if (nums1[0] == nums2[j]) {
dp[j] = 1;
rs = 1;
}
}
for (int i = 1; i < nums1.length; i++) {
int tmpMax = 0;
for (int j = 0; j < nums2.length; j++) {
int tmp = dp[j];
if (nums1[i] == nums2[j]) {
dp[j] = tmpMax + 1; //这里之所以可以直接tmpMax + 1是因为两个相邻的数最多在增加一条线
}
if (tmp > tmpMax) tmpMax = tmp;//tmp实际上记录的是dp[i-1][j];tmpMax实际上记录的是dp[i][j-1]
if (dp[j] > rs) {
rs = dp[j];
}
}
}
return rs;
}
}

View File

@ -0,0 +1,115 @@
package com.markilue.leecode.dynamic;
import org.junit.Test;
/**
*@BelongsProject: Leecode
*@BelongsPackage: com.markilue.leecode.dynamic
*@Author: dingjiawen
*@CreateTime: 2022-12-18 11:15
*@Description:
* TODO 力扣53题 最大子数组和:
* 给你一个整数数组 nums 请你找出一个具有最大和的连续子数组子数组最少包含一个元素返回其最大和
* 子数组 是数组中的一个连续部分
*@Version: 1.0
*/
public class T32_MaxSubArray {
@Test
public void test(){
int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
System.out.println(maxSubArray(nums));
}
@Test
public void test1(){
int[] nums = {-2};
System.out.println(maxSubArray(nums));
}
@Test
public void test2(){
int[] nums = {-2, -1};
int[] nums1 = {-1, -2};
System.out.println(maxSubArray1(nums1));
}
/**
* 本人基础思路当前的状态可以分为要当前这个数或者是不要当前这个数
* TODO 动态规划法子数组要求一定连续
* (1)dp定义:dp[i][0]表示不要当前这个数的最大值dp[i][1]表示要当前这个数的最大值
* (2)dp状态转移方程:
* 1.dp[i][0]=上一个数也不要(包含全都不要了)要上一个数
* dp[i][0]=max(dp[i-1][0],dp[i-1][1])
* 2.dp[i][1]=上一个数不要(一定是num[i]因为子数组要求连续)上一个数要
* dp[i][1]=max(num[i],dp[i-1][1]+num[i])
* (3)dp初始化dp[0][0]=0;dp[0][1]=nums[0]
* (4)dp遍历顺序:从前往后
* (5)dp距离推导以nums = [-2,1,-3,4,-1,2,1,-5,4]为例
* [0 1]
* i=0: 0 -2
* i=1: 0 1
* i=2: 1 -2
* i=3: 1 4
* i=4: 4 3
* i=5: 4 5
* i=6: 5 6
* i=7: 6 1
* i=8: 6 5
* 速度击败5.19%内存击败5.11% 16ms
* @param nums
* @return
*/
public int maxSubArray(int[] nums) {
int[][] dp = new int[nums.length][2];
dp[0][0]=Integer.MIN_VALUE;dp[0][1]=nums[0];
for (int i = 1; i < nums.length; i++) {
dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]);
dp[i][1]=Math.max(nums[i],dp[i-1][1]+nums[i]);
}
//要求子数组要求必须至少一个数所以dp[0][0]=Integer.MIN_VALUE
return Math.max(dp[nums.length-1][0],dp[nums.length-1][1]);
}
/**
* 代码随想录法仅需要算要当前这个数即可
* 以nums = [-2,1,-3,4,-1,2,1,-5,4]为例
* dp:-2,1,-2,4,3,5,6,1,5
* 速度击败43.54%内存击败7.22% 2ms
* @param nums
* @return
*/
public int maxSubArray1(int[] nums) {
int[] dp = new int[nums.length];
dp[0]=nums[0];
int result=dp[0];
for (int i = 1; i < nums.length; i++) {
dp[i]=Math.max(nums[i],dp[i-1]+nums[i]);
if (dp[i] > result) result = dp[i]; // result 保存dp[i]的最大值
}
//要求子数组要求必须至少一个数所以dp[0][0]=Integer.MIN_VALUE
return result;
}
/**
* 一维dp优化
* 以nums = [-2,1,-3,4,-1,2,1,-5,4]为例
* dp:-2,1,-2,4,3,5,6,1,5
* 速度击败100%内存击败39.12% 1ms
* @param nums
* @return
*/
public int maxSubArray2(int[] nums) {
int dp0 =nums[0];
int result=dp0;
for (int i = 1; i < nums.length; i++) {
dp0=Math.max(nums[i],dp0+nums[i]);
if (dp0 > result) result = dp0; // result 保存dp[i]的最大值
}
//要求子数组要求必须至少一个数所以dp[0][0]=Integer.MIN_VALUE
return result;
}
}