力扣123.买卖股票的最佳时机Ⅲ&买卖股票的最佳时机Ⅳ

一.力扣123.买卖股票的最佳时机Ⅲ

题目描述

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

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
示例 4:

输入:prices = [1]
输出:0

提示:

1 <= prices.length <= 105
0 <= prices[i] <= 105

方法一:无脑拆分为五种状态,然后用dp

每一天股票细分为五种状态:

  • 未持股,且未卖过,f0

  • 未持股,卖过一次,f1

  • 持股,第一次持股,f2

  • 持股,第二次持股,f3

  • 未持股,卖过两次,f4

    f 表示在该种状态下当日过后的累计最大金额,有状态方程如下:
    f [ i ] [ 0 ] = f [ i − 1 ] [ 0 ] ; f[i][0]=f[i-1][0]; f[i][0]=f[i1][0];
    f [ i ] [ 1 ] = m a x ( f [ i − 1 ] [ 2 ] + p r i c e s [ i ] , f [ i − 1 ] [ 1 ] ) ; f[i][1]=max(f[i-1][2]+prices[i],f[i-1][1]); f[i][1]=max(f[i1][2]+prices[i],f[i1][1]);
    f [ i ] [ 2 ] = m a x ( f [ i − 1 ] [ 2 ] , − p r i c e s [ i ] ) ; f[i][2]=max(f[i-1][2],-prices[i]); f[i][2]=max(f[i1][2],prices[i]);
    f [ i ] [ 3 ] = m a x ( f [ i − 1 ] [ 3 ] , f [ i − 1 ] [ 1 ] − p r i c e s [ i ] ) ; f[i][3]=max(f[i-1][3],f[i-1][1]-prices[i]); f[i][3]=max(f[i1][3],f[i1][1]prices[i]);
    f [ i ] [ 4 ] = m a x ( f [ i − 1 ] [ 4 ] , f [ i − 1 ] [ 3 ] + p r i c e s [ i ] ) ; f[i][4]=max(f[i-1][4],f[i-1][3]+prices[i]); f[i][4]=max(f[i1][4],f[i1][3]+prices[i]);

代码实现:

int maxProfit(int* prices, int pricesSize){
//f 0:未持股,且未卖过
//f 1:未持股,卖过一次
//f 2:持股,第一次持股
//f 3:持股,第二次持股
//f 4: 未持股,卖过两次
int f[pricesSize][5];
f[0][0]=f[0][1]=f[0][4]=0;
f[0][2]=f[0][3]=-prices[0];
int i;
for(i=1;i<pricesSize;i++)
{
    f[i][0]=f[i-1][0];
    f[i][1]=fmax(f[i-1][2]+prices[i],f[i-1][1]);
    f[i][2]=fmax(f[i-1][2],-prices[i]);
    f[i][3]=fmax(f[i-1][3],f[i-1][1]-prices[i]);
    f[i][4]=fmax(f[i-1][4],f[i-1][3]+prices[i]);
}
return fmax(fmax(f[pricesSize-1][0],f[pricesSize-1][1]),f[pricesSize-1][4]);
}

二.力扣123.买卖股票的最佳时机Ⅳ

题目描述

给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入:k = 2, prices = [2,4,1]
输出:2
解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
示例 2:

输入:k = 2, prices = [3,2,6,5,0,3]
输出:7
解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。

提示:

0 <= k <= 100
0 <= prices.length <= 1000
0 <= prices[i] <= 1000

方法一:划分2k种状态,用dp

上一题最多交易2次,我们划分了五种状态,而本题的状态数是根据输入值k变化的
我们把状态分为两个大类,分别为:

  • 持股状态posession
  • 未持股状态empty

其中每一个大类中又能分为k种小状态,分别为第i次持股,未持股且卖出了i次

用posession[i][j]和empty[i][j]表示第i天j种状态下,当天过完之后的最大累计收益

在此状态划分下稍加思索得出状态方程如下:
p o s e s s i o n [ i ] [ j ] = m a x ( p o s e s s i o n [ i − 1 ] [ j ] , e m p t y [ i − 1 ] [ j − 1 ] − p r i c e s [ i ] ) ; posession[i][j]=max(posession[i-1][j],empty[i-1][j-1]-prices[i]); posession[i][j]=max(posession[i1][j],empty[i1][j1]prices[i]);
e m p t y [ i ] [ j ] = m a x ( e m p t y [ i − 1 ] [ j ] , p o s e s s i o n [ i − 1 ] [ j ] + p r i c e s [ i ] ) ; empty[i][j]=max(empty[i-1][j],posession[i-1][j]+prices[i]); empty[i][j]=max(empty[i1][j],posession[i1][j]+prices[i]);

此外,还需对边界条件和初始值稍加处理,即:

  • 第0天未持股的状态,初始值一定是0
  • 第0天持股的状态,初始值一定是负的第0天的股票价格:-prices[i]
  • 第i天持股状态下,第0次持股的值其实等价于未持股,也将初始值设置为0
  • 第i天未持股状态下且0次卖出的值一定是0,设置初始值为0

最终返回的结果应当是最后一天未持股状态中累计金额最大的结果,可以遍历比较获得

代码实现:

int maxProfit(int k, int* prices, int pricesSize){
   int  posession[pricesSize][k+1],empty[pricesSize][k+1];
   int  i,j,max=-999;
   for(j=0;j<k+1;j++){empty[0][j]=0;posession[0][j]=-prices[0];}
   for(i=1;i<pricesSize;i++){empty[i][0]=0;posession[i][0]=0;}
   for(i=1;i<pricesSize;i++)
   {
      for(j=1;j<k+1;j++)
      {
          //第j次持股
          posession[i][j]=fmax(posession[i-1][j],empty[i-1][j-1]-prices[i]);
          //未持股,且卖了j次
          empty[i][j]=fmax(empty[i-1][j],posession[i-1][j]+prices[i]);
      }
   }
   for(i=0;i<k+1;i++)//获取最大值返回
   {
       if(max<empty[pricesSize-1][i]) max=empty[pricesSize-1][i];
   }
   return max;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值