力扣714. 买卖股票的最佳时机含手续费---动态规划把握全局

714. 买卖股票的最佳时机含手续费

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

示例 1:

输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
输出: 8
解释: 能够达到的最大利润:
在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

注意:
0 < prices.length <= 50000.
0 < prices[i] < 50000.
0 <= fee < 50000.

题解:

首先把握好题意,即同样是 力扣122题 那样那样想进行多少次交易就进行多少次交易,但是每次交易都是会有手续费的,所以这一举措不得不使你的选择变得谨慎,不能再“能买则买,能卖则卖”了,因为那样的话会凭空产生很多没必要的手续费

因此我们从贪心的角度不容易看出来局部的最优能否为全局最优,而贪心其实是动态规划的一种特殊情况,所以不妨直接从动态规划的角度来“把握全局”。

即还是先对题目进行解读:
题目是求(假如你一共有i天)在i天的情况下你通过买卖股票得到的最大收益。而对于动态规划问题,重要是要找准状态。因此我们可以从题目得到我们在进行买卖股票时的有两种状态:

0.手上没股票
1.手上有股票

我们设dp[i][0]为第i天,手上有股票时我们所拥有的金钱数量,所以通过对此状态分解为子问题不难得到状态转移方程:

dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i])

即第i天没股票可能是由于我们的第i天卖了,即第i天参与了;也可能第i天没参与,即前面第i-1天时手上也没股票。

由此可知明白0状态后,1状态同理:
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]-fee);

即第i天有股票可能是因为第i天参与了,所以即在这天买了;也可能第i天没参与,所以手上有股票是前面i-1t天发生的事情。

注意:我们这里把手续费安排到了买股票时就要支付。并且由于我们最后得到的是dp[pricesSize-1][0],是最后一天了手上没有股票时此时剩余的本金数量。而由于我们本来开始时就是没有本金的,所以最后得到的本金其实就是利润了。(并且最后一天一定要手上没有股票,所以一定是0状态)。

代码如下:(二维动态规划)

#define max(a,b) ((a)>(b)?(a):(b))

int maxProfit(int* prices, int pricesSize, int fee){
    if(pricesSize==0)
        return 0;
    int dp[pricesSize][2];
    dp[0][0]=0;
    dp[0][1]=-prices[0]-fee;
    for(int i=1;i<pricesSize;i++)
    {
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
        dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]-fee);
    }
    return dp[pricesSize-1][0];
}

代码:(一维动态规划)

#define max(a,b) ((a)>(b)?(a):(b))

int maxProfit(int* prices, int pricesSize, int fee){
    if(pricesSize==0)
        return 0;
    int dp0[pricesSize],dp1[pricesSize];
    dp0[0]=0;
    dp1[0]=-prices[0]-fee;
    for(int i=1;i<pricesSize;i++)
    {
        dp0[i]=max(dp0[i-1],dp1[i-1]+prices[i]);
        dp1[i]=max(dp1[i-1],dp0[i-1]-prices[i]-fee);
    }
    return dp0[pricesSize-1];
}

代码:(滚动数组进行优化)

#define max(a,b) ((a)>(b)?(a):(b))

int maxProfit(int* prices, int pricesSize, int fee){
    if(pricesSize==0)
        return 0;
    int first,second;
    first=0;
    second=-prices[0]-fee;
    for(int i=1;i<pricesSize;i++)
    {
        first=max(first,second+prices[i]);
        second=max(second,first-prices[i]-fee);
    }
    return first;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向光.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值