题解:学而思编程 最大回撤

【题目来源】

洛谷:最大回撤

【题目描述】

股票价格瞬息万变。在金融市场上,经常需要统计一只股票最大回撤。最大回撤是指投资者在某天买入,在之后的某天卖出,可能造成的最大亏损,它可以反应一只股票在历史上的最坏表现。

给定一个整数序列 \(a_1,a_2,a_3,⋯,a_n\)​,每个 \(a_i\)​ 表示某只股票的在某一天的价格,请计算这只股票的最大回撤。即寻找两个下标满足 \(1≤i≤j≤n\),且 \(a_i−a_j\)​ 最大。

【输入】

第一行,单个整数表示 \(n\)

第二行,\(n\) 个整数表示 \(a_1,a_2,a_3,⋯,a_n\)

【输出】

一行一个整数,表示这只股票的最大回撤,如果价格一直上涨,输出 \(0\)

【输入样例】

5
2 3 7 6 1

【输出样例】

6

【核心思想】

  1. 问题分析:给定长度为 \(n\) 的股票价格序列 \(a_1, a_2, \ldots, a_n\),求最大回撤,即 \(\max_{1 \leq i \leq j \leq n} (a_i - a_j)\)。若价格一直上涨则输出 \(0\)。这是一个前缀最大值 + 线性扫描问题,关键在于维护每个位置之前的历史最高价,然后计算当前价格与历史最高价的差值。

  2. 算法选择

    • 前缀最大值数组max_pre[i] 表示前 \(i\) 个元素中的最大值,即 \(\max_{1 \leq t \leq i} a_t\)
    • 线性扫描求最大差值:遍历每个位置 \(i\),计算 max_pre[i] - a[i],取最大值
  3. 关键步骤

    • 初始化:读取 \(n\)(天数)和股票价格数组 \(a[1..n]\)
    • 计算前缀最大值
      • \(max\_pre[0] = -\infty\)(极小值)
      • 遍历 \(i\)\(1\)\(n\)
        • \(max\_pre[i] = \max(max\_pre[i-1], a_i)\):前 \(i\) 天的历史最高价
    • 计算最大回撤
      • \(ans = -\infty\)
      • 遍历 \(i\)\(1\)\(n\)
        • \(ans = \max(ans, max\_pre[i] - a_i)\):以第 \(i\) 天卖出,之前某天买入的最大亏损
    • 处理非负约束
      • ans < 0(价格一直上涨),输出 \(0\)
      • 否则输出 ans
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\),两次线性遍历
    • 空间复杂度:\(O(n)\),前缀最大值数组 max_pre[0..n](可优化至 \(O(1)\)
  5. 前缀最大值的核心思想

    • 最优子结构:最大回撤要求 \(i \leq j\),前缀最大值 max_pre[j] 恰好是 \(a_j\) 之前(含)的最高价格,保证了买入时间不晚于卖出时间
    • 分离变量:将 \(\max_{i \leq j} (a_i - a_j)\) 拆分为 \(\max_j (\max_{i \leq j} a_i - a_j) = \max_j (max\_pre[j] - a_j)\),将双重循环降为单重
    • 贪心维护max_pre[i] 只需与当前元素比较即可更新,无需重新遍历
    • 空间优化:可用单个变量替代数组,实时维护当前前缀最大值,空间降至 \(O(1)\)
    • 适用于"前缀最值 + 后续差值最优化"类问题,前缀预处理将 \(O(n^2)\) 暴力枚举优化为线性扫描

【算法标签】

模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;  // 定义最大数组长度
int n, a[N], max_pre[N], ans = -1e9;  // 数组长度n,数组a,前缀最大值数组max_pre,答案ans
int main()  // 主函数
{
    cin >> n;  // 输入数组长度
    for (int i=1; i<=n; i++)  // 读取数组元素
        cin >> a[i];  // 输入第i个元素
    max_pre[0] = -1e9;  // 初始化前缀最大值为极小值
    for (int i=1; i<=n; i++)  // 计算前缀最大值
    {
        max_pre[i] = max(max_pre[i-1], a[i]);  // 前i个元素的最大值
    }
    for (int i=1; i<=n; i++)  // 计算最大差值
        ans = max(ans, max_pre[i]-a[i]);  // 更新最大差值
    cout << ans << endl;  // 输出答案
    return 0;  // 程序正常结束
}

【运行结果】

5
2 3 7 6 1
6
posted @ 2026-07-04 14:38  团爸讲算法  阅读(2)  评论(0)    收藏  举报