leecode更新
This commit is contained in:
parent
ec0018c737
commit
8be0b33907
|
|
@ -0,0 +1,131 @@
|
||||||
|
package com.markilue.leecode.dynamic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @BelongsProject: Leecode
|
||||||
|
* @BelongsPackage: com.markilue.leecode.dynamic
|
||||||
|
* @Author: dingjiawen
|
||||||
|
* @CreateTime: 2022-12-13 09:47
|
||||||
|
* @Description:
|
||||||
|
* TODO 力扣123题 买卖股票的最佳时期III:
|
||||||
|
* 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
|
||||||
|
* 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
|
||||||
|
* 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T23_MaxProfit {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
int[] prices={3, 3, 5, 0, 0, 3, 1, 4};
|
||||||
|
System.out.println(maxProfit2(prices));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:这题的核心差别是:最多可以完成两笔交易,本人没有啥思路,被卡在怎么知道卖出了第一次了,以下是代码随想录解法
|
||||||
|
* TODO 动态规划五部曲:核心在于dp的定义和初始化 ->越来越发现,状态转移方程为什么叫状态 转移方程
|
||||||
|
* (观察第i天的情况可以发现,第i天可能有五种状态(从来没有操作;已经买了第一次股票;已经卖出了第一次股票;已经买入了第二次股票;已经卖出了第二次股票))
|
||||||
|
* (1)dp定义:dp[i][0]第i天从来没有操作获得的最大值;dp[i][1]第i天已经买了第一次股票获得的最大值;dp[i][2]第i天已经卖出了第一次股票获得的最大值,以此类推
|
||||||
|
* (2)dp状态转移方程:
|
||||||
|
* 1.dp[i][0] 从来没有操作
|
||||||
|
* dp[i][0]=0
|
||||||
|
* 2.dp[i][1] = 昨天就买了第一次了 ;今天才买第一次
|
||||||
|
* dp[i][1]=max(dp[i-1][1],-price[i])
|
||||||
|
* 3.dp[i][2] = 昨天就卖出了第一次 ;昨天买了第一次的状态,今天才卖
|
||||||
|
* dp[i][2]=max(dp[i-1][2],dp[i-1][1]+price[i])
|
||||||
|
* 4.dp[i][3] = 昨天就买了第二次;昨天卖出的第一次的状态,今天才买第二次
|
||||||
|
* dp[i][3]=max(dp[i-1][3],dp[i-1][2]-price[i])
|
||||||
|
* 5.dp[i][4] = 昨天就卖出了第二次;昨天买入的第二次状态,今天卖了
|
||||||
|
* dp[i][4]=max(dp[i-1][4],dp[i-1][3]+price[i])
|
||||||
|
* (3)dp初始化:dp[0][0]=0 第一天刚买入dp[0][1]=-price[0];第一天刚买刚卖dp[0][2]=0;第一天刚买刚卖又买dp[0][3]=-price[0];第一天刚买刚卖又买又卖dp[0][4]=0
|
||||||
|
* (4)dp遍历顺序:从前往后
|
||||||
|
* (5)dp举例推导:以输入[1,2,3,4,5]为例
|
||||||
|
* [0 1 2 3 4]
|
||||||
|
* i=0 0 -1 0 -1 0
|
||||||
|
* i=1 0 -1 1 -1 1
|
||||||
|
* i=2 0 -1 2 -1 2
|
||||||
|
* i=3 0 -1 3 -1 3
|
||||||
|
* i=4 0 -1 4 -1 4
|
||||||
|
* 速度击败43.68%,内存击败91.87% 20ms
|
||||||
|
* @param prices
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit(int[] prices) {
|
||||||
|
|
||||||
|
int[][] dp = new int[prices.length][5];
|
||||||
|
dp[0][0]=0;
|
||||||
|
dp[0][1]=-prices[0];
|
||||||
|
dp[0][2]=0;
|
||||||
|
dp[0][3]=-prices[0];
|
||||||
|
dp[0][4]=0;
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
dp[i][1]=Math.max(dp[i-1][1],-prices[i]);
|
||||||
|
dp[i][2]=Math.max(dp[i-1][2],dp[i][1]+prices[i]);
|
||||||
|
dp[i][3]=Math.max(dp[i-1][3],dp[i-1][2]-prices[i]);
|
||||||
|
dp[i][4]=Math.max(dp[i-1][4],dp[i-1][3]+prices[i]);
|
||||||
|
}
|
||||||
|
return dp[prices.length-1][4];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动数组优化
|
||||||
|
* 速度击败86.14%,内存击败55.57% 2ms
|
||||||
|
* @param prices
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit1(int[] prices) {
|
||||||
|
int dp0=0;
|
||||||
|
int dp1=-prices[0];
|
||||||
|
int dp2=0;
|
||||||
|
int dp3=-prices[0];
|
||||||
|
int dp4=0;
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
dp1=Math.max(dp1,-prices[i]);
|
||||||
|
dp2=Math.max(dp2,dp1+prices[i]);
|
||||||
|
dp3=Math.max(dp3,dp2-prices[i]);
|
||||||
|
dp4=Math.max(dp4,dp3+prices[i]);
|
||||||
|
}
|
||||||
|
return dp4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论区两次遍历dp法:从高到低一次,从低到高一次。两者相加表示两次交易的最大利润总和,取最大值即可
|
||||||
|
* 速度击败62.14%,内存击败98.29%
|
||||||
|
* 十分的精妙,本质上就是把两次买卖分成了两次T21的maxProfit
|
||||||
|
* 但无法推广到只允许k次交易
|
||||||
|
* @param prices
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit2(int[] prices) {
|
||||||
|
int max = 0;
|
||||||
|
int minVal = prices[0], maxVal = prices[prices.length-1];
|
||||||
|
int[] dp = new int[prices.length];//从低到高,dp[i]表示第i天以及之前的区间所获得的最大利润
|
||||||
|
int[] dp2 = new int[prices.length];//从高到低,dp2[i]表示第i天开始直到最后一天期间所获得的最大利润
|
||||||
|
dp[0] = -prices[0];
|
||||||
|
//这个循环本质上是T21的maxProfit,即寻找从前往后的一次买卖获得最大值
|
||||||
|
for(int i=1;i<prices.length;++i){
|
||||||
|
dp[i] = Math.max(dp[i-1], prices[i]-minVal);
|
||||||
|
minVal = Math.min(prices[i], minVal);
|
||||||
|
}
|
||||||
|
//这个循环本质上是获取第i天后的获得的最大值
|
||||||
|
for(int i=prices.length-2;i>=0;--i){
|
||||||
|
dp2[i] = Math.max(dp2[i+1], maxVal-prices[i]);
|
||||||
|
maxVal = Math.max(maxVal, prices[i]);
|
||||||
|
}
|
||||||
|
//把第i天之前的最大值和第i天之后的最大值相加,找到最大值
|
||||||
|
for(int i=1;i<=prices.length-1;++i){
|
||||||
|
// System.out.println(dp[i-1]+","+dp2[i]);
|
||||||
|
max = Math.max(dp[i-1]+dp2[i], max);
|
||||||
|
}
|
||||||
|
//只买卖一次的,和买卖两次的谁大
|
||||||
|
return Math.max(dp[prices.length-1], max);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package com.markilue.leecode.dynamic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @BelongsProject: Leecode
|
||||||
|
* @BelongsPackage: com.markilue.leecode.dynamic
|
||||||
|
* @Author: dingjiawen
|
||||||
|
* @CreateTime: 2022-12-13 12:00
|
||||||
|
* @Description:
|
||||||
|
* TODO 力扣188题 买卖股票的最佳时期IV:
|
||||||
|
* 给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
|
||||||
|
* 设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
|
||||||
|
* 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T24_MaxProfit {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
int k = 2;
|
||||||
|
int[] prices = {3, 2, 6, 5, 0, 3};
|
||||||
|
System.out.println(maxProfit1(k,prices));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:这题与T23十分的类似:只是将2次交易推广到k次交易,事实上T23的状态转移方程也具有推广性
|
||||||
|
* TODO 动归五部曲:事实上k次交易可以推广到有2*k+1个状态(无操作,第一次买,第一次卖,...,第k次买,第k次买)
|
||||||
|
* (1)dp定义:dp[i][0]表示无操作;dp[i][2*k+1]表示第k次买,dp[i][2*(k+1)]表示第k次卖
|
||||||
|
* (2)dp状态转移方程:
|
||||||
|
* 1.dp[i][2*k+1]=max(dp[i-1][2*k+1],dp[2*k]-prices[i])
|
||||||
|
* 1.dp[i][2*(k+1)]=max(dp[i-1][2*(k+1)],dp[2*k+1]+prices[i])
|
||||||
|
* (3)dp初始化: dp[0][i%2==0]=0;dp[0][i%2==1]=-prices[i]
|
||||||
|
* (4)dp遍历顺序:从前往后
|
||||||
|
* (5)dp举例推导:
|
||||||
|
* 速度击败99.9%,内部击败36.8% 1ms
|
||||||
|
* @param k
|
||||||
|
* @param prices
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit(int k, int[] prices) {
|
||||||
|
|
||||||
|
int[][] dp = new int[prices.length][2 * k + 1];
|
||||||
|
for (int i = 0; i < 2 * k + 1; i++) {
|
||||||
|
dp[0][i] = i % 2 == 0 ? 0 : -prices[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
for (int j = 0; j < k; j++) {
|
||||||
|
dp[i][2*j+1]=Math.max(dp[i-1][2*j+1],dp[i-1][2*j]-prices[i]);
|
||||||
|
dp[i][2*(j+1)]=Math.max(dp[i-1][2*(j+1)],dp[i-1][2*j+1]+prices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[prices.length-1][2*k];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动数组简化
|
||||||
|
* 速度击败58.3%,内存击败78.2% 1ms
|
||||||
|
* @param k
|
||||||
|
* @param prices
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int maxProfit1(int k, int[] prices) {
|
||||||
|
|
||||||
|
int[] dp = new int[2 * k + 1];
|
||||||
|
for (int i = 0; i < 2 * k + 1; i++) {
|
||||||
|
dp[i] = i % 2 == 0 ? 0 : -prices[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < prices.length; i++) {
|
||||||
|
for (int j = 0; j < k; j++) {
|
||||||
|
dp[2*j+1]=Math.max(dp[2*j+1],dp[2*j]-prices[i]);
|
||||||
|
dp[2*(j+1)]=Math.max(dp[2*(j+1)],dp[2*j+1]+prices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[2*k];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue