leecode更新
This commit is contained in:
parent
620b260e4a
commit
ec0018c737
|
|
@ -0,0 +1,209 @@
|
|||
package com.markilue.leecode.dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.dynamic
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-12-12 10:02
|
||||
* @Description:
|
||||
* TODO 力扣121题 买卖股票的最佳时期:
|
||||
* 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
|
||||
* 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
|
||||
* 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class T21_MaxProfit {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int[] price= {7, 1, 5, 3, 6, 4};
|
||||
System.out.println(maxProfit1(price));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
int[] price= {7,6,4,3,1};
|
||||
System.out.println(maxProfit1(price));
|
||||
}
|
||||
|
||||
/**
|
||||
* 思路:第一反应还是一个背包问题:即在第i天所能获得的最大——但似乎是一个O(n^2)复杂度
|
||||
* TODO 动态规划五部曲:
|
||||
* (1)dp定义:dp[i][j]表示在第i天买入在第j天的最大利润
|
||||
* (2)dp状态转移方程:dp[i][j]=max(dp[i][j-1],prices[j]-prices[i],dp[i-1][j])
|
||||
* (3)dp初始化:dp[i][j<=i]=0
|
||||
* (4)dp遍历顺序:
|
||||
* (5)dp举例推导:
|
||||
* 到第198个案例后超出内存限制
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit(int[] prices) {
|
||||
if(prices.length==1){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int[][] dp = new int[prices.length][prices.length];
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
dp[0][i]=Math.max(dp[0][i-1],prices[i]-prices[0]);
|
||||
}
|
||||
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
for (int j = i+1; j < prices.length; j++) {
|
||||
dp[i][j]=Math.max(Math.max(dp[i][j-1],prices[j]-prices[i]),dp[i-1][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return dp[prices.length-2][prices.length-1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:尝试一遍遍历,思路,遇见负数就将现在的值置为最小值,本质上是一种贪心
|
||||
* 速度击败55.26%,内存击败71.51% 2ms
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit1(int[] prices) {
|
||||
if(prices.length==1){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int max=0;
|
||||
int min=prices[0];
|
||||
|
||||
for (int i = 1; i < prices.length; i++) {
|
||||
if(prices[i]<min) {
|
||||
min = prices[i];
|
||||
continue;
|
||||
}
|
||||
max=Math.max(prices[i]-min,max);
|
||||
}
|
||||
|
||||
return max;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方贪心法:与本人的贪心类似,比本人快第一个if,并将Math.max替换为下面的else if
|
||||
* 速度击败100%,内存击败30.17%
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit2(int prices[]) {
|
||||
int minprice = Integer.MAX_VALUE;
|
||||
int maxprofit = 0;
|
||||
for (int i = 0; i < prices.length; i++) {
|
||||
if (prices[i] < minprice) {
|
||||
minprice = prices[i];
|
||||
} else if (prices[i] - minprice > maxprofit) {
|
||||
maxprofit = prices[i] - minprice;
|
||||
}
|
||||
}
|
||||
return maxprofit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论区从右往左动态规划法:比较巧妙
|
||||
* 巧妙在于:当天(i)的买入最大利润=i+1天以后的最大值-当天的价格
|
||||
* 而i+1天以后的最大值=i+1天的利润+(i+1)时的股票价格
|
||||
* 所以当天利润=i+1天的利润+(i+1)时的股票价格-当天的价格
|
||||
* 速度击败30.8%,内存击败98%
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit3(int[] prices) {
|
||||
int len=prices.length;
|
||||
int[] dp=new int[len];//每天买入股票对应能获取的最大利润
|
||||
int max=0;//最大利润
|
||||
dp[len-1]=0;//最后一天买入的话利润为0
|
||||
for(int i=len-2;i>=0;i--){
|
||||
//因为利润最大的话,当然是选择价格最高的时候卖出
|
||||
//所以dp[i+1]=(第i+1天之后最高价格)- prices[i+1];
|
||||
//如果dp[i+1]=0,那么第i天之后最高价格只可能是prices[i+1]
|
||||
//如果dp[i+1]>0就是dp[i+1]+prices[i+1];
|
||||
//所以第i天买入能获得的最大利润就是profit
|
||||
//如果第i天价格比之后都高的话,那么profit<0
|
||||
int profit=dp[i+1]+prices[i+1]-prices[i];
|
||||
dp[i]=profit>0 ? profit : 0;
|
||||
max=profit>max ? profit : max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码随想录动态规划法(版本一):
|
||||
* TODO 动态规划五部曲:
|
||||
* (1)dp定义:dp[i][0]表示第i天持有股票的最多现金;dp[i][1]表示第i天不持有股票的最多现金
|
||||
* (2)dp状态转移方程:
|
||||
* 1.dp[i][0] 注意:题目规定只能买入一次,所以有下面的推导
|
||||
* dp[i][0]表示当天持有,所以可以从两个情况获得:昨天就持有了;或者今天才买入
|
||||
* dp[i][0]=max(dp[i-1][0],-price[i])
|
||||
* 2.dp[i][1]
|
||||
* dp[i][1]表示当天不持有,所以也可以从两种情况获得:昨天不持有;或者今天才卖出
|
||||
* dp[i][1]=max(dp[i-1][1],price[i]+dp[i-1][0])
|
||||
* (3)dp初始化:dp[0][0]=-price[0];dp[0][1]=0
|
||||
* (4)dp遍历顺序:从状态转移方程可以看出从前往后
|
||||
* (5)dp距离推导:输入:[7,1,5,3,6,4]为例,dp数组状态如下:
|
||||
* [0,1]
|
||||
* i=0 -7 0
|
||||
* i=1 -1 0
|
||||
* i=2 -1 4
|
||||
* i=3 -1 4
|
||||
* i=4 -1 5
|
||||
* i=5 -1 5
|
||||
* 速度击败6.7%,内存击败89.24%
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit4(int[] prices) {
|
||||
if (prices == null || prices.length == 0) return 0;
|
||||
int length = prices.length;
|
||||
// dp[i][0]代表第i天持有股票的最大收益
|
||||
// dp[i][1]代表第i天不持有股票的最大收益
|
||||
int[][] dp = new int[length][2];
|
||||
int result = 0;
|
||||
dp[0][0] = -prices[0];
|
||||
dp[0][1] = 0;
|
||||
for (int i = 1; i < length; i++) {
|
||||
dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);
|
||||
dp[i][1] = Math.max(dp[i - 1][0] + prices[i], dp[i - 1][1]);
|
||||
}
|
||||
return dp[length - 1][1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码随想录动态规划法(版本二):滚动数组,记录前一天的即可
|
||||
* 速度击败55.26%,内存击败16.18%
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit5(int[] prices) {
|
||||
int[] dp = new int[2];
|
||||
// 记录一次交易,一次交易有买入卖出两种状态
|
||||
// 0代表持有,1代表卖出
|
||||
dp[0] = -prices[0];
|
||||
dp[1] = 0;
|
||||
// 可以参考斐波那契问题的优化方式
|
||||
// 我们从 i=1 开始遍历数组,一共有 prices.length 天,
|
||||
// 所以是 i<=prices.length
|
||||
for (int i = 1; i <= prices.length; i++) {
|
||||
// 前一天持有;或当天买入
|
||||
dp[0] = Math.max(dp[0], -prices[i - 1]);
|
||||
// 如果 dp[0] 被更新,那么 dp[1] 肯定会被更新为正数的 dp[1]
|
||||
// 而不是 dp[0]+prices[i-1]==0 的0,
|
||||
// 所以这里使用会改变的dp[0]也是可以的
|
||||
// 当然 dp[1] 初始值为 0 ,被更新成 0 也没影响
|
||||
// 前一天卖出;或当天卖出, 当天要卖出,得前一天持有才行
|
||||
dp[1] = Math.max(dp[1], dp[0] + prices[i - 1]);
|
||||
}
|
||||
return dp[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package com.markilue.leecode.dynamic;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.dynamic
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-12-12 12:23
|
||||
* @Description:
|
||||
* TODO 力扣122题 买卖股票的最佳时机 II:
|
||||
* 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
|
||||
* 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
|
||||
* 返回 你能获得的 最大 利润 。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class T22_MaxProfit {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int[] prices = {7, 1, 5, 3, 6, 4};
|
||||
System.out.println(maxProfit(prices));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
int[] prices = {1,2,3,4,5};
|
||||
System.out.println(maxProfit(prices));
|
||||
}
|
||||
|
||||
/**
|
||||
* 思路:这题实际上在贪心的时候遇到过,这里使用动态规划法:
|
||||
* 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]+price[i])
|
||||
* 2.dp[i][1]=昨天留了今天没买;昨天没留今天买了
|
||||
* dp[i][1]=max(dp[i-1][1],dp[i-1][0]-price[i]))
|
||||
* (3)dp初始化:dp[0][0]=0;dp[0][1]=-price[0]
|
||||
* (4)dp遍历顺序:从前往后
|
||||
* (5)dp举例推导:以prices = [7,1,5,3,6,4]为例:
|
||||
* [0 1]
|
||||
* i=0 0 -7
|
||||
* i=1 0 -1
|
||||
* i=2 4 -1
|
||||
* i=3 4 1
|
||||
* i=4 7 1
|
||||
* i=5 7 3
|
||||
* 速度击败24.78%,内存击败28.24% 3ms
|
||||
*/
|
||||
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 < 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]);
|
||||
}
|
||||
return dp[prices.length-1][0];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 对上述思路进行简化:使用滑动数组记录上次
|
||||
* 速度击败82.36%,内存击败66.41%
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方贪心法:本质上就是利润累加
|
||||
* @param prices
|
||||
* @return
|
||||
*/
|
||||
public int maxProfit2(int[] prices) {
|
||||
int ans = 0;
|
||||
int n = prices.length;
|
||||
for (int i = 1; i < n; ++i) {
|
||||
ans += Math.max(0, prices[i] - prices[i - 1]);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue