题目

编写程序,解决经典单调栈(Monotonic Stack)问题:给定一个长度为 N 的整数数组,寻找数组中每个元素右侧“第一个比它自身更大”的元素数值,若右侧不存在更大元素则填 -1。从暴力 O(N^2) 双重循环的瓶颈出发,利用单调递减栈在 O(N) 线性时间内一次性得出全量答案。

输入格式:无需外部输入(内置测试序列)。

输出格式:输出原数组与计算出的每个元素右侧第一个更大元素序列。

数据范围与约定:时间复杂度严格 O(N),每个元素最多进出栈各一次。

思路与算法

1. 暴力算法的缺陷
外层枚举当前数,内层向右扫描,最坏情况(如单调递减数组 [5, 4, 3, 2, 1])下耗时 O(N^2)。

2. 单调栈单调性维持
从右向左逆向扫描数组(或者正向扫描维护索引栈)。维持栈内元素自底向上严格单调递减:当新元素 nums[i] 准备入栈时,栈顶所有 <= nums[i] 的元素均被彻底淘汰弹栈(因为它们永远不可能作为左侧更远元素的第一个更大者),此时新的栈顶即为答案!

3. O(N) 均摊分析
虽然内层有 while 循环,但每个元素在整个流程中最多仅执行 1 次压栈与 1 次弹栈,总摊还操作步数严格 ≤ 2N。

完整程序

#include <iostream>
#include <vector>
#include <stack>

std::vector<int> nextGreaterElements(const std::vector<int>& nums) {
    int n = nums.size();
    std::vector<int> result(n, -1);
    std::stack<int> st; // 单调递减栈:存储元素数值

    // 从右往左逆序遍历
    for (int i = n - 1; i >= 0; --i) {
        // 弹出所有不大于当前元素的无用值
        while (!st.empty() && st.top() <= nums[i]) {
            st.pop();
        }

        // 栈顶即为右侧第一个更大元素
        if (!st.empty()) {
            result[i] = st.top();
        }

        // 当前元素入栈
        st.push(nums[i]);
    }

    return result;
}

int main() {
    std::vector<int> nums = {2, 7, 3, 5, 4, 6, 8};

    std::cout << "原数组序列:       ";
    for (int x : nums) std::cout << x << "  ";
    std::cout << "\n";

    std::vector<int> nge = nextGreaterElements(nums);

    std::cout << "右侧首个更大元素: ";
    for (int x : nge) std::cout << x << "  ";
    std::cout << "\n";

    return 0;
}

运行示例

输出:

原数组序列:       2  7  3  5  4  6  8  
右侧首个更大元素: 7  8  5  6  6  8  -1