121. 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
思路
限制:只能买卖一次,这个就是和第二题的区别,所以对于这道题不用动态规划也是可以做出来的,只要求出数组的最大区间就可以了。所以遍历找到最大值和最小值,计算差值就是最后的值。
思路一 求最大差值区间
遍历一次,记录左侧最小值,求差值的最大值
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let min = Number.MAX_VALUE;
let result = 0;
for (let i = 0; i < prices.length; i++) {
min = Math.min(prices[i], min);
result = Math.max(prices[i] - min, result);
}
return result;
};
思路二:动态规划思路
动态规划最重要的是确定dp数组的含义,以及递推公式。这道题,每天有2种状态,一种是当天持有股票,一个是不持有股票,所以用二维数组表示,数组长度是价格的长度,数组的每一项有2个选项,存储当前持有股票的最大值和不持有股票的最大值。因为是求最大值,所以递推公式需要取max值,而最后的结果取到最后一天为止不持有股票的最大值dp[len - 1][1]
。
- 含义:
- dp[i][0]: 第i天持有股票的最大价值,
- dp[i][1]: 第i天不持有股票的最大价值
- 递推公式:
dp[i][0] = max(dp[i-1][0], -prices[i])
前天持有股票,今天不变以及前天不持有股票,今天买入的最大值dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])
, 前天不持有股票,今天依然不持有,以及今天卖出的最大值
- 初始化:
- dp[0][0] = -prices[0],
- dp[0][1] = 0
/**
* @param {} prices
*/
var maxProfit = function(prices) {
const len = prices.length;
const dp = new Array(len).fill(0).map(item => new Array(2).fill(0));
dp[0][0] = 0 - prices[0];
for (let i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][0], 0 - prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
return dp[len - 1][1]
}
题目二 122. 买卖股票的最佳时机 II
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
思路
和上一题的区别是可以多次买卖股票,但是同一时刻只能持有一只股票。
思路1 贪心算法
求这段区间内上升段的所有和,就是只保留上升区间,下降的丢掉,因为会降低。如果把这个区段内想象为间隔为1的区间的所有区间,求最大和,这样求得时候把负数都丢掉,只保留正数就是最大值。
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let maxProfit = 0;
for (let i = 1; i < prices.length; i++) {
if (prices[i] - prices[i - 1] > 0) {
maxProfit += prices[i] - prices[i - 1];
}
}
return maxProfit;
}
思路2 动态规划
这个就和第一道题一模一样了,基本是通用的公式。
- 含义:
- dp[i][0]: 第i天持有股票的最大价值,
- dp[i][1]: 第i天不持有股票的最大价值
- 递推公式:
dp[i][0] = max(dp[i-1][0], dp[i - 1][1] -prices[i])
前天持有股票,今天不变以及前天不持有股票,今天买入的最大值,这里是和上一道的唯一区别地方, 多次买卖,那第i-1天不持有股票的价值不一定是0,可能是之前积累的价值,所以将0换为dp[i-1][1]dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])
, 前天不持有股票,今天依然不持有,以及今天卖出的最大值
- 初始化:
- dp[0][0] = -prices[0],
- dp[0][1] = 0
var maxProfit = function(prices) {
const len = prices.length;
const dp = new Array(len).fill(0).map(item => new Array(2).fill(0));
dp[0][0] = 0 - prices[0];
dp[0][1] = 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][1];
}
总结
咱就是说动态规划这个到底该怎么想出来,就算第二题的贪心算法也是没想出来的。😔