力扣刷题—股票买卖集合

labuladong大神的详细讲解——股票问题
力扣股票问题-合集

1.穷举框架

采用穷举思想,就是把【所有的状态】都列举出来,再找出每个【状态】对应的【选择】。
我们要穷举所有的【状态】,穷举的目的是根据对应的【选择】更新状态。

for 状态1 in 状态1的所有取值:
	for 状态2 in 状态2的所有取值:
		for ... ...
			dp[状态1][状态2][...] = 择优(选择1,选择2...)

1.1.具体到股票的问题,每天都有3种选择:买入、卖出、无操作。

但是,并不是每天都可以任意选择这3种,因为:

  • 1.sell必须在buy之后;
  • 2.buy必须在sell之后(第1次除外);
  • 3.rest操作,也分2种状态,1种是buy之后的rest,1种是sell之后的rest;
  • 4.而且还有交易次数k的限制,即:buy必须在k>0时才可以进行。‘

1.2.回归本题目

这个问题的状态只有3个:

  • 1.天数day;
  • 2.当天允许交易的最大次数K;
  • 3.当前持有的状态(1:持有股票,0:未持有);
dp[i][k][0 or 1]
0 <= i <= n-1   n表示天数
1 <= k <= KK表示最多交易次数
此问题共有n × K × 2 种状态
for 0 <= i < n :
	for 1 <= k <= K:
		for s in {0,1}:
			dp[i][k][s] = max(buy, sell, rest)
  • 自然语言描述3维数组的含义:
    dp[3][2][1]:表示今天是第3天,手上有股票,至今最多进行2次交易;
    dp[2][3][1]:表示今天是第2天,手上没股票,至今最多进行3次交易;
  • 我们的目标
    求dp[n-1][K][0],即最后1天,最多允许K次交易,所能获取的最大利润;

1.3.状态转移框架

力扣刷题—股票买卖集合_第1张图片

  • 根据此图写状态转移方程:
    注意:最大交易次数仅在buy的时候-1(其实也可以选择sell的时候-1,但只能选择其一!)
	解释:今天我没有持有股票,因为:
		1.我昨天也没持有,今天选择rest;
		2.我昨天持有了,今天选择sell。	
dp[i][k][0] = max( dp[i-1][k][0] , dp[i-1][k][1] + price[i] )
			  max( 选择rest      ,  选择sell )
			  
	解释:今天我持有股票,因为:
		1.我昨天持有,今天选择rest;
		2.我昨天没有,今天选择buy。	
dp[i][k][1] = max( dp[i-1][k][1] , dp[i-1][k-1][0] - price[i] )
			  max( 选择rest,        选择buy )

2.剑指 Offer 63. 股票的最大利润(仅1次交易)

一次买卖股票的最大利润

  • 假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少? 力扣刷题—股票买卖集合_第2张图片

1.解题思路(贪心算法)

  • 1.从头向后遍历,寻找股票价值最低的值,即为low;
  • 2.也同时计算当前的price[i]与low的差值,并且每次只保存最大的值。
class Solution {
    public int maxProfit(int[] prices) {
		1.low初始值设为负无穷大,你品,你细品!
        int low = Integer.MAX_VALUE;
        2.返回值res初始设为0,因为总不能赔钱!
        int res = 0;  
        3.从头遍历
        for (int i = 0; i < prices.length; i++) {
        	3.1.滑动取出最小值
            low = Math.min(low,prices[i]); 
            3.2.利用贪心算法,求出最大的值,并存入返回值
            res = Math.max(prices[i]-low,res); 
        }
        return res;
    }
}

2.解题思路(动态规划)

class Solution {
    public int maxProfit(int[] prices) {
        int day = prices.length;
        int state = 2;
        int[][] dp = new int[day+1][state];
        1.考虑好特殊值
        dp[0][0] = 0;  开始前1天,没有股票,利润为0
        dp[0][1] = Integer.MIN_VALUE; 开始前1天,有股票,利润为负无穷大,表示不可能
        for (int i = 1; i < day+1; i++) {
        	2.动态规划相互依赖
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i-1]);
            dp[i][1] = Math.max(dp[i-1][1],0-prices[i-1]);
        }
        return dp[day][0];
    }
}

3.买卖股票的最佳时机 II(无限次交易)

  • 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

  • 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

  • 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
    力扣刷题—股票买卖集合_第3张图片

1.解题思路(动态规划)

  • 1.因为无限次,所以交易次数就不是约束条件了;
  • 2.不同相邻前后2天之间相互依赖;
  • 3.考虑好特殊值的问题,dp[0][0],dp[0][1];
class Solution {
    public int maxProfit(int[] prices) {
        int day = prices.length;
        int state = 2;
        int[][] dp = new int[day+1][state];
        1.特殊值考虑好
        dp[0][0] = 0;
        dp[0][1] = Integer.MIN_VALUE;
        for (int i = 1; i < day+1; i++) {
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i-1]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i-1]);
        }
        return dp[day][0];
    }
}

2.解题思路(贪心算法思想)

  • 1.利润分割思想,相邻两天都进行交易;
  • 2.只取利润为正的,并求和。
    力扣刷题—股票买卖集合_第4张图片
    力扣刷题—股票买卖集合_第5张图片
class Solution {
    public int maxProfit(int[] prices) {
        int day = prices.length;
        int res = 0;
        
        for (int i = 1; i < day; i++) {
        	1.只要 正 的利润
            res += Math.max(0,prices[i]-prices[i-1]);
        }
        return res;
    }
}

714. 买卖股票的最佳时机含手续费(可无限次买卖)

力扣刷题—股票买卖集合_第6张图片

class Solution {
    public int maxProfit(int[] prices, int fee) {
        
        int day = prices.length;
        int state = 2;
        1.建立动态数组  dp[i][0]表示,第i天 不持有股票,手中有多少钱
        			   dp[i][1]表示,第i天  持有股票,手中有多少钱
        int[][] dp = new int[day+1][state];
        2.base case0天不持有股票, 手中有 0 元
        	        第0天 持有股票, 手中有 负无穷大的 钱
        	              防止误判,因为第1天 要在for 循环做判断
        dp[0][0] = 0;
        dp[0][1] = Integer.MIN_VALUE;

        for (int i = 1; i < day+1; i++) {
        	表示第 i 天不持有股票, 手中有多少钱, 是前一天也没持有钱多, 还是把前一天的卖了 钱多 ?
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i-1]);
        	表示第 i 天 持有股票, 手中有多少钱, 是前一天也持有钱多, 还是前一天没有,今天买入 钱多 ?
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i-1]-fee);
        }
        return dp[day][0];

    }
}

你可能感兴趣的:(力扣刷题思考,算法,动态规划)