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;
}