问题描述
小R近期表现出色,公司决定以股票的形式给予奖励,并允许他在市场上进行交易以最大化收益。给定一个数组,数组中的第 i 个元素代表第 i 天的股票价格。小R需要设计一个算法来实现最大利润。
股票交易规则如下:
- 小R可以多次买卖股票,但在买入新的股票前必须卖出之前的股票。
- 每次卖出股票后存在一天的冷冻期,在冷冻期内小R不能购买股票。
你的任务是帮助小R计算出在遵守交易规则的情况下能够获得的最大利润。
stocks: 一个整数列表,表示连续几天内的股票价格。
测试样例
样例1:
输入:
stocks = [1, 2]
输出:1
样例2:
输入:
stocks = [2, 1]
输出:0
样例3:
输入:
stocks = [1, 2, 3, 0, 2]
输出:3
样例4:
输入:
stocks = [2, 3, 4, 5, 6, 7]
输出:5
样例5:
输入:
stocks = [1, 6, 2, 7, 13, 2, 8]
输出:12
-
状态定义:
hold[i]:表示第i天持有股票时的最大利润。sold[i]:表示第i天卖出股票后的最大利润。rest[i]:表示第i天处于冷冻期(即前一天卖出股票)时的最大利润。
-
状态转移:
hold[i]可以从hold[i-1](前一天持有股票)或者rest[i-1] - stocks[i](前一天处于冷冻期,今天买入股票)转移而来。sold[i]只能从hold[i-1] + stocks[i](前一天持有股票,今天卖出)转移而来。rest[i]可以从rest[i-1](前一天处于冷冻期)或者sold[i-1](前一天卖出股票)转移而来。
-
初始状态:
hold[0]初始化为-stocks[0](第一天买入股票)。sold[0]和rest[0]初始化为0。
-
最终结果:
- 最终的最大利润应该是
sold[n-1]和rest[n-1]中的最大值,因为最后一天可能处于冷冻期或者卖出股票。
- 最终的最大利润应该是
根据以上思路,我们可以开始编写代码。以下是代码框架:
public class Main {
public static int solution(int[] stocks) {
if (stocks == null || stocks.length == 0) {
return 0;
}
int n = stocks.length;
int[] hold = new int[n];
int[] sold = new int[n];
int[] rest = new int[n];
// 初始化状态
hold[0] = -stocks[0];
sold[0] = 0;
rest[0] = 0;
// 状态转移
for (int i = 1; i < n; i++) {
hold[i] = Math.max(hold[i-1], rest[i-1] - stocks[i]);
sold[i] = hold[i-1] + stocks[i];
rest[i] = Math.max(rest[i-1], sold[i-1]);
}
// 最终结果
return Math.max(sold[n-1], rest[n-1]);
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution(new int[]{1, 2}) == 1);
System.out.println(solution(new int[]{2, 1}) == 0);
System.out.println(solution(new int[]{1, 2, 3, 0, 2}) == 3);
System.out.println(solution(new int[]{2, 3, 4, 5, 6, 7}) == 5);
System.out.println(solution(new int[]{1, 6, 2, 7, 13, 2, 8}) == 12);
}
}
代码解释:
hold[i]表示第i天持有股票时的最大利润。sold[i]表示第i天卖出股票后的最大利润。rest[i]表示第i天处于冷冻期时的最大利润。- 通过状态转移方程,我们逐步更新这些状态数组,最终得到最大利润。
1. 动态规划(Dynamic Programming)
动态规划是解决本题的核心方法。通过定义状态和状态转移方程,我们可以逐步计算出最优解。
-
状态定义:
hold[i]:表示第i天持有股票时的最大利润。sold[i]:表示第i天卖出股票后的最大利润。rest[i]:表示第i天处于冷冻期时的最大利润。
-
状态转移方程:
hold[i] = max(hold[i-1], rest[i-1] - stocks[i]):第i天持有股票的最大利润可以从第i-1天持有股票的状态转移而来,或者从第i-1天处于冷冻期并买入股票的状态转移而来。sold[i] = hold[i-1] + stocks[i]:第i天卖出股票的最大利润只能从第i-1天持有股票并卖出股票的状态转移而来。rest[i] = max(rest[i-1], sold[i-1]):第i天处于冷冻期的最大利润可以从第i-1天处于冷冻期的状态转移而来,或者从第i-1天卖出股票的状态转移而来。
2. 状态初始化
在动态规划中,初始状态的定义非常重要。本题中:
hold[0] = -stocks[0]:第一天买入股票的最大利润。sold[0] = 0:第一天卖出股票的最大利润(实际上不可能,因为第一天无法卖出)。rest[0] = 0:第一天处于冷冻期的最大利润。
3. 状态更新
通过循环遍历每一天的股票价格,根据状态转移方程更新 hold、sold 和 rest 数组。
4. 最终结果
最终的最大利润应该是 sold[n-1] 和 rest[n-1] 中的最大值,因为最后一天可能处于冷冻期或者卖出股票。
5. 时间复杂度和空间复杂度
- 时间复杂度:
O(n),其中n是股票价格数组的长度。我们只需要遍历一次数组。 - 空间复杂度:
O(n),因为我们使用了三个长度为n的数组来存储状态。
总结
本题通过动态规划的方法,定义了三个状态数组来表示不同状态下的最大利润,并通过状态转移方程逐步更新这些状态,最终得到最大利润。动态规划的核心思想是将复杂问题分解为子问题,并通过存储子问题的解来避免重复计算,从而提高效率。