LeetCode 121. 买卖股票的最佳时机 DP题解,熟悉简单DP问题。
121. 买卖股票的最佳时机#
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
李煜东著《算法竞赛进阶指南》,摘录如下::
动态规划三要素:
- 状态;
- 阶段;
- 决策;
动态规划求解的三个基本条件:
- 子问题重叠性;
- 无后效性;
- 最优子结构性质;
DP
解题关键要素:
要素 |
|
状态表示 |
dp[i] 表示当前能买入的最低价格、prices[i] 表示当前天卖出的价格; |
阶段划分 |
子序列结尾; |
转移方程 |
dp[i] = Min(prices(0,i)) |
边界 |
dp[0] = prices[0] |
目标 |
Max(prices[i]-dp[i]) (0<=i<n) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public int maxProfit(int[] prices) {
int n = prices.length;
// dp数组存储当前时刻前买入的最低价格
int[] dp = new int[n];
dp[0] = prices[0];
int ans = 0;
for (int i = 1; i < prices.length; i++) {
dp[i] = Math.min(dp[i - 1], prices[i]);
// 判断当前时刻卖出是否划算?
if (prices[i] - dp[i] > ans) {
ans = prices[i] - dp[i];
}
}
return ans;
}
|
观察发现,上述dp[]
其实无需保留每一项的最小值,我们仅需记录窗口内的最小值即可,可通过滚动数组来优化空间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/**
* 使用滚动数组优化:只需维护窗口内的最低买入价格即可
*/
static class ScrollArray {
/*
* 执行用时:
* 2 ms
* , 在所有 Java 提交中击败了
* 58.30%
* 的用户
* 内存消耗:
* 58.2 MB
* , 在所有 Java 提交中击败了
* 5.05%
* 的用户
* 通过测试用例:
* 211 / 211
*/
public int maxProfit(int[] prices) {
int minBuyPrice = prices[0];
int ans = 0;
for (int i = 1; i < prices.length; i++) {
minBuyPrice = Math.min(minBuyPrice, prices[i]);
ans = Math.max(prices[i] - minBuyPrice, ans);
}
return ans;
}
}
|
复杂度分析#
整个过程仅需遍历一次入参数组,时间复杂度O(n)
。
写法1我们定义了prices
大小的dp
数组,空间复杂度O(n)
。
写法2优化了空间占用,空间复杂度O(1)
。