From 933ab9105117ba61be9b997810981b7b235af571 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Wed, 22 Feb 2023 14:54:05 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/dynamic/T27_LengthOfLIS.java | 2 +- .../leecode/dynamic/second/T26_MaxProfit.java | 96 +++++++++++++++++++ .../dynamic/second/T27_LengthOfLIS.java | 44 +++++++++ .../dynamic/second/T28_FindLengthOfLCIS.java | 67 +++++++++++++ .../dynamic/second/T29_FindLength.java | 86 +++++++++++++++++ 5 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T26_MaxProfit.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T27_LengthOfLIS.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T28_FindLengthOfLCIS.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T29_FindLength.java diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/T27_LengthOfLIS.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/T27_LengthOfLIS.java index 7c42893..76ebcf9 100644 --- a/Leecode/src/main/java/com/markilue/leecode/dynamic/T27_LengthOfLIS.java +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/T27_LengthOfLIS.java @@ -96,7 +96,7 @@ public class T27_LengthOfLIS { r = mid - 1; } } - d[pos + 1] = nums[i]; + d[pos + 1] = nums[i];//把第一个小于的位置替换成这个数//并不影响原本的长度,只有后续比他更长了,才会影响他的长度 } } return len; diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T26_MaxProfit.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T26_MaxProfit.java new file mode 100644 index 0000000..3e41d8a --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T26_MaxProfit.java @@ -0,0 +1,96 @@ +package com.markilue.leecode.dynamic.second; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.dynamic.second + *@Author: markilue + *@CreateTime: 2023-02-22 10:35 + *@Description: + * TODO 力扣714题 买卖股票的最佳时机含手续费: + * 给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。 + * 你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。 + * 返回获得利润的最大值。 + * 注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。 + *@Version: 1.0 + */ +public class T26_MaxProfit { + + @Test + public void test(){ + int[] prices = {1, 3, 2, 8, 4, 9}; + int fee = 2; + System.out.println(maxProfit(prices,fee)); + } + + /** + * 思路:仅是每笔交易的时候包含了手续费;在每次买的时候加上手续费即可 + * 速度击败50.42% 内存击败89.43% + * @param prices + * @param fee + * @return + */ + public int maxProfit(int[] prices, int fee) { + + int[][] dp = new int[prices.length][2]; + + dp[0][0] = 0; + dp[0][1] = -prices[0] - fee; + + for (int i = 1; i < prices.length; i++) { + dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]); + dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i]-fee); + } + + return dp[dp.length-1][0]; + + } + + + /** + * 一维dp优化 + * 速度击败99.96% 内存击败36.47% 3ms + * @param prices + * @param fee + * @return + */ + public int maxProfit1(int[] prices, int fee) { + + int dp0 = 0; + int dp1 = -prices[0] - fee; + int temp; + + for (int i = 1; i < prices.length; i++) { + temp=dp0; + dp0=Math.max(dp0,dp1+prices[i]); + dp1=Math.max(dp1,temp-prices[i]-fee); + } + + return dp0; + } + + + /** + * 贪心算法: 核心在于 何时才真正卖出 + * @param prices + * @param fee + * @return + */ + public int maxProfit2(int[] prices, int fee) { + + int buy=prices[0]+fee; + int sum=0; + + for (int price : prices) { + if(price+feebuy){ + sum += price - buy;//假装排除计算收益 + buy = price;//后期如果有数比他大,那么就是计算加上的p-buy增值收益 + } + } + + return sum; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T27_LengthOfLIS.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T27_LengthOfLIS.java new file mode 100644 index 0000000..5d8038f --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T27_LengthOfLIS.java @@ -0,0 +1,44 @@ +package com.markilue.leecode.dynamic.second; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.dynamic.second + *@Author: markilue + *@CreateTime: 2023-02-22 10:58 + *@Description: + * TODO leecode300 最长递增子序列: + * 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 + * 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 + *@Version: 1.0 + */ +public class T27_LengthOfLIS { + + + /** + * 思路:注意是子序列,可以删除前后元素,找最长 因为可以删除 所以可以将状态分为两种 :要当前的词 不要当前的词 TODO 不知道如何保存状态,未能做出 + * TODO dp五部曲: + * 1.dp定义: dp[i][0]表示不要当前当前的词的最长序列长度 dp[i][1]表示要当前的词的最长序列长度 + * 2.dp状态转移方程: //因为没法保存状态,所以只能暴力依次比较 时间复杂度O(n^2) + * 3.dp初始化: + * 4.dp遍历顺序: + * 5.dp举例推导: + * @param nums + * @return + */ + public int lengthOfLIS(int[] nums) { + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + int result = 0; + for (int i = 0; i < dp.length; i++) { + for (int j = 0; j < i; j++) {//本质上还是依次比较寻找最大的 + if (nums[i] > nums[j]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + if (dp[i] > result) result = dp[i]; // 取长的子序列 + } + return result; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T28_FindLengthOfLCIS.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T28_FindLengthOfLCIS.java new file mode 100644 index 0000000..10d5587 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T28_FindLengthOfLCIS.java @@ -0,0 +1,67 @@ +package com.markilue.leecode.dynamic.second; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.dynamic.second + *@Author: markilue + *@CreateTime: 2023-02-22 11:47 + *@Description: + * TODO 力扣674题 最长连续递增序列: + * 给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。 + * 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] , + * 那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。 + *@Version: 1.0 + */ +public class T28_FindLengthOfLCIS { + + /** + * 思路:不同之处在于 要连续递增 所以要维护的是一个子数组,由于是连续的,所以比较 + * TODO DP五部曲; + * 1.dp定义: + * 2.dp状态转移方程: + * 3.dp初始化: + * 4.dp遍历顺序: + * 5.dp举例推导: + * @param nums + * @return + */ + public int findLengthOfLCIS(int[] nums) { + + int maxLength = 1; + int curLength = 1; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] > nums[i - 1]) { + curLength++; + } else { + curLength = 1;//小于就重置 + } + + if (curLength > maxLength) maxLength = curLength; + } + return maxLength; + + } + + + /** + * 动态规划法 + * @param nums + * @return + */ + public int findLengthOfLCIS1(int[] nums) { + int nowLength=1; + int[] dp = new int[nums.length]; + dp[0]=1; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] > nums[i-1]) { + nowLength+=1;//状态递推 + }else { + nowLength=1; + } + dp[i]=Math.max(dp[i-1],nowLength); + } + return dp[nums.length-1]; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T29_FindLength.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T29_FindLength.java new file mode 100644 index 0000000..0bfab48 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T29_FindLength.java @@ -0,0 +1,86 @@ +package com.markilue.leecode.dynamic.second; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.dynamic.second + *@Author: markilue + *@CreateTime: 2023-02-22 11:56 + *@Description: + * TODO 力扣718题 最长重复子数组: + * 给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 。 + *@Version: 1.0 + */ +public class T29_FindLength { + + @Test + public void test() { + int[] nums1 = {0, 1, 1, 1, 1}; + int[] nums2 = {1, 0, 1, 0, 1}; + System.out.println(findLength(nums1, nums2)); + } + + + /** + * 思路: + * TODO DP五部曲: + * 1.dp定义:dp[i][j]表示 使用nums1[0-i]和nums2[0-j]所返回的最长长度 + * 2.dp状态转移方程: + * dp[i][j] 可以是 不要nums2[j] 不要nums1[i] 或者nums[i]==nums[j] + * dp[i][j] if(nums[i-1]!=nums[j-1]) max(dp[i-1][j],dp[i][j-1]) + * else dp[i-1][j-1]+1 + * 3.dp初始化:为了初始化方便,取nums[i-1]!=nums[j-1]的关系 dp[i][0]=0; dp[0][j]=0; + * 4.dp遍历顺序: + * 5.dp举例推导: + * @param nums1 + * @param nums2 + * @return + */ + public int findLength(int[] nums1, int[] nums2) { + + int[][] dp = new int[nums1.length + 1][nums2.length + 1]; + int result = 0; + + 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; + //因为是子数组,不是子序列,所以一不想等,就直接等于0了,不做处理 + if (result < dp[i][j]) result = dp[i][j]; +// else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + + return result; + + } + + + /** + * 一维dp优化 + * @param nums1 + * @param nums2 + * @return + */ + public int findLength1(int[] nums1, int[] nums2) { + + int[] dp = new int[nums2.length + 1]; + int result = 0; + + for (int i = 1; i < nums1.length + 1; i++) { + for (int j = dp.length - 1; j >= 1; j--) { + //返许遍历,因为dp[j]要用到dp[i-1] + if (nums1[i - 1] == nums2[j - 1]) { + dp[j] = dp[j - 1] + 1; + }else { + dp[j]=0; //TODO 特别需要注意: 如果不等需要重新赋值,避免不覆盖的情况;而二维的时候不用,因为不用重复利用 + } + //因为是子数组,不是子序列,所以一不想等,就直接等于0了,不做处理 + if (result < dp[j]) result = dp[j]; + } + } + + return result; + + } +}