给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。
题解
动态规划
对于每一天来说,有两种状态,持有股票和不持有股票,对于动态规划来说,我们要能够找到与上一个状态的关系,也就是找出状态方程,所以我们定义一个二维数组dp
dp[i][0]
:表示第i天不持有股票所获得的最大利润dp[i][1]
:表示第i天持有股票所获得的最大利润
显然,我们要求的是最后一天不持有股票所获得的最大利润,那怎么推出动态方程呢?
对于前一天,也有这两种状态,那怎么由前一天推出这一天的状态呢,有两种情况
- 对于今天不持有股票的,有可能是前一天就不持有股票,也有可能是前一天持有股票,在今天卖掉了,那我们求的是最大利润,所以要取两者中最大的
- 同理也可以得出今天持有股票的情况
dp[i][0] = Math.max(dp[i - 1][1] + prices[i], dp[i - 1][0])
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i])
初始化
对于第一天来说,不持有股票利润就是0,持有股票利润是-prices[0]
具体代码
var maxProfit = function(prices) {
// 动态规划解法
const len = prices.length
const dp = new Array(len).fill([]).map(v => new Array(2))
dp[0][0] = 0, dp[0][1] = - prices[0]
for(let i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][1] + prices[i], dp[i - 1][0])
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i])
}
return dp[len - 1][0]
};
贪心算法
这道题也可以使用贪心算法,但可能比较难想的出。。。
贪心算法要能够先找到子问题,那对于买卖股票来说,我们可以分成几个买卖的阶段,比如第1天买第2天卖出,第3天买第4天卖出,然后把每个阶段的利润合起来就是整个买卖过程的总利润了。这就变成通过这些子问题的最优解找到整个问题的最优解了
那对于买一个子问题也就是每一个买卖的过程,比如price[3] - price[1],第一天买入第3天卖出,那price[3] - price[1]也可以表示为(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])
所以可以表示为相邻两天买卖的利润,但我们求的是最大利润,所以只选择利润值为正的就好
对于这里,为什么可以转化为这样,我的理解是:
- 对于每一天,我都拿钱去买股票,然后第二天卖出去
- 那如果卖出去亏了的话,那这一次就不买了
- 那如果卖出去赚钱了,即卖出的前大于买入的钱,两种之差就是利润了
具体代码
var maxProfit = function(prices) {
// 贪心解法
let result = 0
const len = prices.length
for(let i = 1; i < len; i++) {
if(prices[i] - prices[i - 1] > 0) {
result += prices[i] - prices[i - 1]
}
}
return result
};