题解:学而思编程 股票买卖

【题目来源】

学而思编程:股票买卖

【题目描述】

给定一支股票接下来 \(n\) 天的价格,设计一个算法计算出最大的利润。

每天你可以进行买入或者卖出,或者不进行任何操作,但是需要遵守以下条件:

  • 你不能同时参与多笔交易(你必须在再次买入前卖出之前的股票)。
  • 卖出股票后,你无法在第二天买入股票(即冷冻期为 \(1\) 天)。

【输入】

第一行一个整数 \(n(1≤n≤10^5)\),表示一共有 \(n\) 天。

第二行一共有 \(n\) 个整数 \(a_i(1≤a_i≤10^9)\),表示第 \(i\) 天的价格。

【输出】

输出一行,包含一个整数,表示最大的利润。

【输入样例】

5
2 3 4 1 3

【输出样例】

3

【核心思想】

  1. 问题分析:给定 \(n\) 天的股票价格 \(a_i\),每天可以买入、卖出或不操作,但不能同时持有多只股票(再次买入前必须卖出),且卖出后有 \(1\) 天冷冻期(第二天不能买入)。求最大利润。这是一个状态机 DP 问题,需要设计多个状态表示不同的持仓和冷冻情况。

  2. 算法选择

    • 状态机 DP(线性 DP):定义多个状态表示不同的交易状态
    • 状态设计
      • 状态 \(0\):手中没有股票,且不在冷冻期(可以买入)
      • 状态 \(1\):手中持有股票
      • 状态 \(2\):手中没有股票,但处于冷冻期(刚卖出,不能买入)
  3. 关键步骤

    • 初始化\(dp[0][0] = 0\)(第 \(0\) 天没有股票,利润为 \(0\)),其他状态初始化为负无穷
    • 状态转移
      • \(dp[i][0] = \max(dp[i-1][0], dp[i-1][2])\):状态 \(0\) 可以从状态 \(0\) 不操作,或从状态 \(2\) 冷冻期结束转移
      • \(dp[i][1] = \max(dp[i-1][1], dp[i-1][0] - a[i])\):状态 \(1\) 可以从状态 \(1\) 继续持有,或从状态 \(0\) 买入(花费 \(a[i]\)
      • \(dp[i][2] = dp[i-1][1] + a[i]\):状态 \(2\) 只能从状态 \(1\) 卖出股票转移(获得 \(a[i]\)
    • 答案\(\max(dp[n][0], dp[n][2])\),最后不能持有股票
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),一次遍历完成状态转移
    • 空间复杂度:\(O(n)\),DP 数组存储,可优化至 \(O(1)\)
  5. 状态机 DP 的核心思想

    • 状态设计:根据题目约束设计合理的状态,本题用三个状态表示持仓和冷冻情况
    • 状态转移:明确每个状态可以从哪些状态转移而来,确保状态转移的完备性
    • 最优子结构:当前最优解由子问题的最优解组合而成
    • 空间优化:由于只依赖前一天的状态,可以用滚动数组优化至 \(O(1)\)
    • 适用于有复杂约束的序列决策问题,如股票交易、任务调度等

【算法标签】

线性DP-一维

【代码详解】

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
const int N = 1e5 + 5;
int n, a[N], dp[N][5];  // dp[i][j]: 前i天,状态j的最大收益

signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];  // 第i天的股价
    }
    memset(dp, -0x3f, sizeof(dp));  // 初始化为负无穷
    dp[0][0] = 0;  // 第0天,没有股票

    for (int i = 1; i <= n; i++)
    {
        // 状态0: 没有股票,不操作
        dp[i][0] = max(dp[i - 1][0], dp[i - 1][2]);
        // 状态1: 持有股票
        dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - a[i]);
        // 状态2: 卖出股票后的冷冻期
        dp[i][2] = dp[i - 1][1] + a[i];
    }
    cout << max(dp[n][0], dp[n][2]);  // 最后不能持有股票
    return 0;
}

【运行结果】

5
2 3 4 1 3
3
posted @ 2026-06-14 10:47  团爸讲算法  阅读(6)  评论(0)    收藏  举报