题目描述
给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
方法一 贪心
解题思路
当天股票价格比前一天高即可进行一次盈利操作,多次盈利操作累加起来就可得出最大利润
代码示例
const maxProfit = function(prices) {
let result = 0;
let n = prices.length;
for (let i = 1; i < n; ++i) {
result += Math.max(0, prices[i] - prices[i - 1]);
}
return result;
};
复杂度分析
时间复杂度:O(n),其中n为数组的长度。我们只需要遍历一次数组即可
空间复杂度:O(1)。只需要常数空间存放若干变量。
方法二 动态规划
解题思路
每天交易结束后只可能存在手里有一支股票或者没有股票的状态
- dp[i][0] 表示第i天手中没有股票的最大利润,没有股票可能是前一天时就没有股票,或者前一天有股票,第i天卖出,公式如下:
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i])
- dp[i][1] 表示第i天手中持有股票的最大利润,持有股票可能是前一天时就持有股票,或者前一天没有股票,第i天买入,公式如下
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
代码实现
const maxProfit = function (prices) {
const len = prices.length;
const dp = new Array(len).fill(0).map(v => new Array(2).fill(0));
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (let i = 1; i < len; 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]);
}
return dp[len - 1][0];
};
复杂度分析
时间复杂度:O(n),其中 n 为数组的长度。一共有 2n 个状态,每次状态转移的时间复杂度为 O(1),因此时间复杂度为 O(2n)=O(n)
空间复杂度:O(n)。我们需要开辟 O(n) 空间存储动态规划中的所有状态。如果使用空间优化,空间复杂度可以优化至 O(1)
优化空间复杂度
只需要关注今天的状态和前一天的状态即可
const len = prices.length;
let cash = 0;
let hold = -prices[0];
// 前一天持有现金的最大利润
let preCash = cash;
// 前一天持有股票的最大利润
let preHold = hold;
for (let i = 1; i < len; i++) {
// 第i天持有现金的最大利润
cash = Math.max(preCash, preHold + prices[i]);
// 第i天持有股票的最大利润
hold = Math.max(preHold, preCash - prices[i]);
// 更新前一天持有现金的最大利润
preCash = cash;
// 更新前一天持有股票的最大利润
preHold = hold;
}
return cash;
空间复杂度:O(1)。我们只需要常量个变量。