携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
题目介绍
题目分析
该题相比于买卖股票的最佳时机含冷冻期比较简单,没有冷冻期,所以只需要区分买入状态和卖出状态即可,唯一不同的是买入卖出时需要支付一次手续(注意:不是买入、卖出都需要支付手续费,一次完整交易只需要支付一次手续费即可)。
状态转移分析
dp[i][j] 表示第i天第j种状态所拥有的最大收益值,其中j有两种状态:
0: 买入状态,可能是今天买入,也可能是之前某一天买入
1:卖出状态,可能是今天卖出,也可能是之前某一天卖出
dp[i][0]: dp[i-1][0] dp[i-1][1] - prices[i] 取二者最大值
dp[i][1]: dp[i-1][1] dp[i-1][0] + prices[i] - fee 当天卖出要收手续费,取二者最大值
初始化: dp[0][0] = -prices[i] 第一天买入 dp[0][1] = -fee 买入卖出 收手续费
dp[i] 由dp[i-1]推导出来,所以应该从前往后遍历
最终收益最大值一定是卖出状态,dp[prices.length-1][1]
代码实现
var maxProfit = function(prices, fee) {
/**
dp[i][j] 表示第i天j种状态的收益最大值
j = 0 ;买入状态
j = 1 卖出状态
dp[i][0] = dp[i-1][0] dp[i-1][1] - prices[i]
dp[i][1] = dp[i-1][1] dp[i-1] + prices[i] - 2
dp[0][0] = -prices[0]
dp[0][1] = 0
*/
const dp = Array.from(Array(prices.length),() => Array(2).fill(0))
dp[0][0] = -prices[0]
dp[0][1] = 0
for(let i = 1;i<prices.length;i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] - prices[i])
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] + prices[i] - fee)
}
return dp[prices.length-1][1]
};
贪心算法
其实本题也可采用贪心算法实现,每次都在最低点买入,最高点卖出(减去手续费),如果收益值为正则卖出,累计计算每次收益的和,计算利润时,可能有多次计算利润,最后一次计算利润才是真正意义的卖出
var maxProfit = function(prices, fee) {
let minPrice = prices[0]
let result = 0
for(let i = 1;i<prices.length;i++){
if(prices[i]<minPrice){
minPrice = prices[i] // 每次更新最小值
}
if(prices[i]>minPrice&&prices[i]-minPrice<=fee){
continue; // 收益小于手续费不操作
}
if(prices[i] - minPrice > fee){
result += prices[i] - minPrice - fee; //收益值为正则卖出
minPrice = prices[i] - fee; // 每次计算收益并不是真正的卖出,可能是持有,只有真正卖出才计算手续费, 减去fee避免重读计算手续费
}
}
return result;
};