From 607b5f6af2bc302947ea76b3658661a6b9ee1db5 Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Tue, 21 Feb 2023 13:56:59 +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/second/T21_MaxProfit.java | 104 +++++++++++++++ .../leecode/dynamic/second/T22_MaxProfit.java | 78 ++++++++++++ .../leecode/dynamic/second/T23_MaxProfit.java | 119 ++++++++++++++++++ .../leecode/dynamic/second/T24_MaxProfit.java | 87 +++++++++++++ .../leecode/dynamic/second/T25_MaxProfit.java | 86 +++++++++++++ 5 files changed, 474 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T21_MaxProfit.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T22_MaxProfit.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T23_MaxProfit.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T24_MaxProfit.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/dynamic/second/T25_MaxProfit.java diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T21_MaxProfit.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T21_MaxProfit.java new file mode 100644 index 0000000..637810e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T21_MaxProfit.java @@ -0,0 +1,104 @@ +package com.markilue.leecode.dynamic.second; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.dynamic.second + *@Author: markilue + *@CreateTime: 2023-02-21 09:50 + *@Description: + * TODO 力扣121 买卖股票的最佳时机: + * 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 + * 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 + * 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。 + *@Version: 1.0 + */ +public class T21_MaxProfit { + + @Test + public void test() { + int[] prices = {7, 1, 5, 3, 6, 4}; + System.out.println(maxProfit2(prices)); + } + + + /** + * 思路:事实上思路是一致的:将当前收益分为手上有股票和手上没有股票 注意只能买卖一次 + * TODO DP五部曲: + * 1.dp定义: dp[i][0]表示第i天手上没有股票的最大收益;dp[i][1]表示第i天手上有股票的最大收益 + * 2.dp状态转移方程: + * 1.dp[i][0] 昨天没有今天没买 ; 昨天有今天卖了 + * dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]) + * 2.dp[i][1] 昨天有今天没卖 ; 昨天没有今天买了 + * dp[i][1]=max(dp[i-1][1],-prices[i]) + * 3.dp初始化:dp[0][0]=0; dp[0][1]=-price[0]; + * 4.dp遍历顺序:从前往后 + * 5.dp举例推导: + * 速度击败5.69% 内存击败89.6% + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + + int[][] dp = new int[prices.length][2]; + dp[0][0] = 0; + dp[0][1] = -prices[0]; + + for (int i = 1; i < dp.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], -prices[i]); + } + + return dp[dp.length - 1][0]; + + } + + + /** + * 一维dp优化 + * 速度击败54.5% 内存击败66.9% + * @param prices + * @return + */ + public int maxProfit1(int[] prices) { + + int dp0 = 0; + int dp1 = -prices[0]; + + for (int i = 1; i < prices.length; i++) { + dp0 = Math.max(dp0, dp1 + prices[i]); + dp1 = Math.max(dp1, -prices[i]); + } + + return dp0; + + } + + + /** + * 贪心算法 + * 速度击败100% 内存击败42.58% + * @param prices + * @return + */ + public int maxProfit2(int[] prices) { + + int minPrice = prices[0]; + int maxProfit = 0; + int curProfit = 0; + + //只买卖一次 + for (int i = 1; i < prices.length; i++) { + if (minPrice > prices[i]) { + minPrice = prices[i]; + continue; + } + curProfit = prices[i] - minPrice; + if (maxProfit < curProfit) maxProfit = curProfit; + } + + return maxProfit; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T22_MaxProfit.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T22_MaxProfit.java new file mode 100644 index 0000000..e8d5054 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T22_MaxProfit.java @@ -0,0 +1,78 @@ +package com.markilue.leecode.dynamic.second; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.dynamic.second + *@Author: markilue + *@CreateTime: 2023-02-21 10:39 + *@Description: + * TODO 力扣122 买卖股票的最佳时机II: + * 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。 + * 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。 + * 返回 你能获得的 最大 利润 。 + *@Version: 1.0 + */ +public class T22_MaxProfit { + + /** + * 与上一题不同之处在于:收益可以累加 + * 所以 dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0]-prices[i]); + * 速度击败25.56% 内存击败9.38% 3ms + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + int[][] dp = new int[prices.length][2]; + dp[0][0] = 0; + dp[0][1] = -prices[0]; + + for (int i = 1; i < dp.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]); + } + + return dp[dp.length - 1][0]; + + } + + + /** + * 一维dp优化 + * 速度击败83.44% 内存击败49.3% 1ms + * @param prices + * @return + */ + public int maxProfit1(int[] prices) { + + int dp0 = 0; + int dp1 = -prices[0]; + + for (int i = 1; i < prices.length; i++) { + dp0 = Math.max(dp0, dp1 + prices[i]); + dp1 = Math.max(dp1, dp0 - prices[i]); + } + + return dp0; + + } + + + /** + * 贪心 + * 速度击败83.44% 内存击败81.45% 1ms + * @param prices + * @return + */ + public int maxProfit2(int[] prices) { + + int profit = 0; + + for (int i = 1; i < prices.length; i++) { + int curDiff = prices[i] - prices[i - 1]; + if (curDiff > 0) profit += curDiff;//因为可以当天买当天卖 + } + + return profit; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T23_MaxProfit.java b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T23_MaxProfit.java new file mode 100644 index 0000000..bf50032 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/dynamic/second/T23_MaxProfit.java @@ -0,0 +1,119 @@ +package com.markilue.leecode.dynamic.second; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.dynamic.second + *@Author: markilue + *@CreateTime: 2023-02-21 10:48 + *@Description: + * TODO 力扣123 买卖股票的最佳时机III: + * 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 + * 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + *@Version: 1.0 + */ +public class T23_MaxProfit { + + + /** + * 思路:不同之处在于规定了最多只能完成两笔交易 所以将状态定为五种 + * TODO DP五部曲: + * 1.dp定义:dp[i][0],dp[i][1],dp[i][2],dp[i][3]分别代表 第i天 第一次买入 第一次卖出 第二次买入 第二次卖出 + * 2.dp状态转移方程: + * 1.dp[i][0] 由于是第一次买入,所以之前是没有收益的 + * dp[i][0]=max(dp[i-1][0],-prices[i]) + * 2.dp[i][1] 由于是第一次卖出 + * dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]) + * 3.dp[i][2] 由于是第二次买入 + * dp[i][2]=max(dp[i-1][2],dp[i-1][1]-prices[i]) + * 4.dp[i][3] 由于是第一次卖出 + * dp[i][3]=max(dp[i-1][3],dp[i-1][2]+prices[i]) + * 3.dp初始化:dp[i][0]=-price[0],dp[i][1]=0,dp[i][2]=-price[0],dp[i][3]=0 + * 4.dp遍历顺序: + * 5.dp举例推导: 以prices = [3,3,5,0,0,3,1,4]为例 + * [0 1 2 3] + * 3: -3 0 -3 0 + * 3: -3 0 -3 0 + * 5: -3 2 -3 2 + * 0: 0 2 2 2 + * 0: 0 2 2 2 + * 3: 0 3 2 5 + * 1: 0 3 2 5 + * 4: 0 4 2 6 + * 速度击败23.76% 内存击败80.68% 35ms + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + + int[][] dp = new int[prices.length][4]; + dp[0][0] = -prices[0]; + dp[0][1] = 0; + dp[0][2] = -prices[0]; + dp[0][3] = 0; + + for (int i = 1; i < prices.length; i++) { + dp[i][0]=Math.max(dp[i-1][0],-prices[i]); + dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]); + dp[i][2]=Math.max(dp[i-1][2],dp[i-1][1]-prices[i]); + dp[i][3]=Math.max(dp[i-1][3],dp[i-1][2]+prices[i]); + } + + + return dp[dp.length-1][3]; + + } + + + /** + * 滚动数组优化 + * 速度击败87.55% 内存击败42.27% 2ms + * @param prices + * @return + */ + public int maxProfit1(int[] prices) { + + + int dp0 = -prices[0]; + int dp1 = 0; + int dp2 = -prices[0]; + int dp3 = 0; + + for (int i = 1; i < prices.length; i++) { + dp0=Math.max(dp0,-prices[i]); + dp1=Math.max(dp1,dp0+prices[i]); + dp2=Math.max(dp2,dp1-prices[i]); + dp3=Math.max(dp3,dp2+prices[i]); + } + + + return dp3; + + } + + + /** + * 官方最快:贪心? 本质上跟上面一样还是动态规划,只是将dp[0]的推导变成了贪心的模式 + * 速度击败100% 内存击败30.8% 1ms + * @param prices + * @return + */ + public int maxProfit2(int[] prices) { + int min=prices[0];//第一次买入的最小价格 + int p1=0;//第一次卖出的收益 + + int max1=Integer.MIN_VALUE;//第二次买入的最大收益 + int p2=0; //第二次卖出的收益 + + for(int i=1;imin) + p1=Math.max(p1,prices[i]-min); + else if(prices[i]