本文专注于记录我如何使用AI完成算法刷题练习,以此来分享如何高效利用AI刷题。
#80股票市场交易策略优化
问题描述
为了奖励你在上个季度的优秀表现,公司决定发给你一部分股票,你可以在市场上自由交易。
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格。
设计一个算法计算出最大利润。
在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)
- 卖出股票后,你无法在第二天买入股票(即冷冻期为 1 天)
输入格式
一个数组:[1,2,3,0,2]
数据约束
见题目描述
输出格式
最大的收益数值
输入样例
[1,2]
[2,1]
[1,2,3,0,2]
[2,3,4,5,6,7]
[1,6,2,7,13,2,8]
输出样例
1
0
3
5
12
思路
为了求解这个股票交易问题,我们需要设计一个动态规划算法,考虑到“冷冻期”这一约束条件,即在卖出股票后,必须等待一天才能再次买入。
我们可以定义一个状态机来表示每一天的不同状态:
- 持有股票:表示我们当前手里有股票。
- 不持有股票,且刚刚卖出:表示我们当前不持有股票,并且刚刚卖出了一只股票(冷冻期状态)。
- 不持有股票,且没有刚刚卖出:表示我们当前不持有股票,而且不是冷冻期状态(即之前没有卖出过股票)。 我们使用三个变量来记录这三种状态:
hold[i]:表示在第i天结束时,持有股票的最大利润。sold[i]:表示在第i天结束时,不持有股票且刚刚卖出的最大利润。rest[i]:表示在第i天结束时,不持有股票且没有刚刚卖出的最大利润。
状态转移方程
-
hold[i]:如果我们在第i天持有股票,可以来自以下两种情况:- 前一天已经持有股票并且今天没有卖出:
hold[i-1] - 前一天没有股票并且今天买入股票:
rest[i-1] - prices[i]
因此,
hold[i] = max(hold[i-1], rest[i-1] - prices[i]) - 前一天已经持有股票并且今天没有卖出:
-
sold[i]:如果我们在第i天卖出股票,可以来自以下情况:- 前一天持有股票并且今天卖出:
hold[i-1] + prices[i]
因此,
sold[i] = hold[i-1] + prices[i] - 前一天持有股票并且今天卖出:
-
rest[i]:如果我们在第i天不持有股票且不是冷冻期状态,可以来自以下两种情况:- 前一天已经没有股票且没有刚刚卖出:
rest[i-1] - 前一天刚刚卖出股票并且今天不进行买入:
sold[i-1]
因此,
rest[i] = max(rest[i-1], sold[i-1]) - 前一天已经没有股票且没有刚刚卖出:
初始化状态
-
第
0天:hold[0] = -prices[0]:买入股票时的利润为负数。sold[0] = 0:没有卖出股票。rest[0] = 0:没有进行任何交易。
最终结果
在最后一天,我们的最大利润应该是 max(sold[n-1], rest[n-1]),即不持有股票并且刚刚卖出或没有刚刚卖出的最大利润。
代码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int solution(vector<int> stocks) {
int n = stocks.size();
if (n == 0) return 0; // 如果股票价格数组为空,直接返回0利润
// 定义三个状态数组
vector<int> hold(n, 0), sold(n, 0), rest(n, 0);
// 初始状态
hold[0] = -stocks[0]; // 第一天买入股票,利润为负股票价格
sold[0] = 0; // 第一天没有卖出股票,利润为0
rest[0] = 0; // 第一天没有进行任何交易,利润为0
// 从第二天开始动态规划计算
for (int i = 1; i < n; i++) {
// 当前持有股票的最大利润
hold[i] = max(hold[i-1], rest[i-1] - stocks[i]); // 持有股票可以来自两种情况:1. 前一天继续持有 2. 前一天休息并且今天买入股票
// 当前卖出股票的最大利润
sold[i] = hold[i-1] + stocks[i]; // 卖出股票只能来自前一天持有股票并在今天卖出
// 当前不持有股票且没有刚刚卖出的最大利润
rest[i] = max(rest[i-1], sold[i-1]); // 休息状态可以来自两种情况:1. 前一天休息 2. 前一天卖出股票并且今天继续休息
}
// 最终结果是最后一天卖出股票或休息的最大利润
return max(sold[n-1], rest[n-1]);
}
int main() {
// 测试用例
cout << (solution({1, 2}) == 1) << endl;
cout << (solution({2, 1}) == 0) << endl;
cout << (solution({1, 2, 3, 0, 2}) == 3) << endl;
cout << (solution({2, 3, 4, 5, 6, 7}) == 5) << endl;
cout << (solution({1, 6, 2, 7, 13, 2, 8}) == 12) << endl;
return 0;
}
代码说明
关键点:
- 我们需要计算出每天持有、卖出和休息三种状态下的最大利润。
- 由于有冷冻期(卖出股票后必须等一天才能再次买入),我们要分别维护每种状态的利润。
代码复杂度:
- 时间复杂度:O(n),其中 n 是股票价格的天数。我们只进行了一次数组遍历,因此时间复杂度为 O(n)。
- 空间复杂度:O(n),由于我们使用了三个数组来保存不同状态下的利润,因此空间复杂度为 O(n)。