leecode更新
This commit is contained in:
parent
600003ba7f
commit
29fe083026
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue