如何利用AI刷题基础篇6——高效刷题|豆包MarsCode AI刷题

91 阅读5分钟

本文专注于记录我如何使用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


思路

为了求解这个股票交易问题,我们需要设计一个动态规划算法,考虑到“冷冻期”这一约束条件,即在卖出股票后,必须等待一天才能再次买入。

我们可以定义一个状态机来表示每一天的不同状态:

  1. 持有股票:表示我们当前手里有股票。
  2. 不持有股票,且刚刚卖出:表示我们当前不持有股票,并且刚刚卖出了一只股票(冷冻期状态)。
  3. 不持有股票,且没有刚刚卖出:表示我们当前不持有股票,而且不是冷冻期状态(即之前没有卖出过股票)。 我们使用三个变量来记录这三种状态:
  • 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)。