LeetCode上有6道股票问题,他们其实就是数组中是否存在数的差值最大,加上各种限制
文章目录
数组中两个数的差值最大
数组中找出2对数使得其对应的差值的和最大
数组中找出k对数使得其对应的差值的和最大
数组中找出不限制对数使其对应的差值的和最大
数组中找出跳跃一个元素的对数使得差值的和最大
数组中找出不限制对数使得其差值最大(有附加损失)
这里我们用
动态规划
,利用状态进行穷举,我们具体到每一天,看看总共有几种可能的状态,再找出每个状态对应的选择。我们要穷举所有的状态,穷举的目的是根据对应的选择更新状态。听起来很抽象,只要记住[状态]和选择两个词就行,
for 状态1 in 状态1的所有取值:
for 状态2 in 状态2的所有取值:
for ...
dp[状态1][状态2][...] = 择优(选择1,选择2...)
比如说这个问题,每天都有三种「选择」:买入、卖出、无操作,我们用 buy, sell, rest 表示这三种选择。但问题是,并不是每天都可以任意选择这三种选择的,因为 sell 必须在 buy 之后,buy 必须在 sell 之后。那么 rest 操作还应该分两种状态,一种是 buy 之后的 rest(持有了股票),一种是 sell 之后的 rest(没有持有股票)。而且别忘了,我们还有交易次数 k 的限制,就是说你 buy 还只能在 k > 0 的前提下操作。
这个问题的状态有3个,第一个是天数,第二个是允许交易的最大次数,第三个是当钱的持有状态(寄之前说的reset的状态,我们不妨用1表示持有,0表示没有持有),然后我们用一个三维数组就可以装下这几种状态的全部组合
dp[i][k][0 or 1]
0 <= i <= n-1, 1 <= k <= K
n 为天数,大 K 为最多交易数
此问题共 n × K × 2 种状态,全部穷举就能搞定。
for 0 <= i < n:
for 1 <= k <= K:
for s in {
0, 1}:
dp[i][k][s] = max(buy, sell, rest)
状态转移方程:
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
baseCase
dp[0][k][0]= 0
dp[0][k][1] =Integer.MinVale/2
dp[i][0][1] = Integer.MinvAL/2
dp[i][0][0]=0
LeetCode121 买股票的最佳时机
package com.zj.FDynamicProgramming.taolu;
/**
* @Author Zhou Jian
* @Date 2020/8/8
*/
public class Problem121 {
/**
* dp[i][k][0] 第i天允许操作k次不持有股票获利最大
* dp[i][k][1] 第i天允许操作k次不持有股票获利最大
*
* dp[i][k][0] = max(dp[i-1][k][0],dp[i-1][k][1]+nums[i-1]
* dp[i][k][1] = max(dp[i-1][k][1],dp[i-1][k-1][0]-nums[i-1])
*
* dp[0][k][0] = 0
* dp[i][0][1] = 不可能
*
* @param prices
* @return
*/
public int maxProfit(int[] prices) {
if(prices==null||prices.length==0) return 0;
int[][] dp = new int[prices.length+1][2];
dp[0][0] = 0;
for(int i=0;i<prices.length+1;i++){
if(i==0){
dp[i][0] = 0;
dp[i][1]=Integer.MIN_VALUE;
continue;
}
dp[i][0] = Math.max(dp[i-1][0],dp[