diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/T31_MaxUncrossedLines.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/T31_MaxUncrossedLines.java new file mode 100644 index 0000000..c3b0f44 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/T31_MaxUncrossedLines.java @@ -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 tmpMax) tmpMax = tmp;//tmp实际上记录的是dp[i-1][j];tmpMax实际上记录的是dp[i][j-1] + if (dp[j] > rs) { + rs = dp[j]; + } + } + } + return rs; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/T32_MaxSubArray.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/T32_MaxSubArray.java new file mode 100644 index 0000000..6b25b75 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/T32_MaxSubArray.java @@ -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; + + } +}