懒加载技巧优化栈增减操作(力扣3629)

问题解构

力扣第 3629 题是 "设计一个支持增量操作的栈" (Design a Stack With Increment Operation)。该问题要求设计一个定长栈,除了支持标准的 pushpop 操作外,还需要支持一个特殊的 increment(k, val) 操作,该操作会将栈底的前 k 个元素(即最早入栈的元素)全部增加 val。如果栈中元素少于 k 个,则将所有元素增加 val

核心难点increment 操作如果直接遍历栈底的前 k 个元素进行加法,时间复杂度为 O(k),在最坏情况下(k 等于栈容量)可能达到 O(n),导致多次操作后整体性能下降。因此,需要设计一种高效的数据结构,使得 pushpopincrement 操作的时间复杂度均为 O(1)

方案推演

为了实现 O(1) 时间复杂度的 increment 操作,可以采用 "惰性增量" (Lazy Increment)或 "差分数组"(Difference Array)的思想。具体方案如下:

  1. 数据结构设计

    • 使用一个数组 stack 存储栈中的元素。
    • 使用另一个数组 inc 作为增量数组,inc[i] 表示从栈底到位置 i(含)的所有元素需要累加的增量值。
    • 维护一个整数 top 表示栈顶指针(指向下一个可插入位置)。
  2. 操作实现

    • push(x):如果栈未满,将 x 存入 stack[top],并将 inc[top] 初始化为 0,然后 top++
    • pop():如果栈为空,返回 -1。否则,top--。由于 inc[top] 可能包含了从栈底到该位置的累积增量,因此实际弹出的值应为 stack[top] + inc[top]。此外,为了将增量传递给更靠近栈顶的元素(如果存在),需要将 inc[top-1] 加上 inc[top](即增量上浮),然后将 inc[top] 重置为 0。
    • increment(k, val):该操作只需更新增量数组。具体地,将 inc[min(k-1, top-1)] 增加 val。因为 inc[i] 表示从栈底到 i 的累积增量,所以只需在边界处增加 val,后续在 pop 时通过上浮传递增量。
  3. 时间复杂度分析

    • push:O(1)。
    • pop:O(1)。
    • increment:O(1)。

具体实现

以下是基于上述方案的 Java 代码实现,包含详细注释。

java 复制代码
class CustomStack {
    private int[] stack; // 存储栈元素
    private int[] inc;   // 增量数组,inc[i] 表示从栈底到 i 位置的累积增量
    private int top;     // 栈顶指针,指向下一个可插入位置
    private int maxSize; // 栈的最大容量

    public CustomStack(int maxSize) {
        this.maxSize = maxSize;
        stack = new int[maxSize];
        inc = new int[maxSize];
        top = 0; // 栈初始为空
    }

    public void push(int x) {
        if (top >= maxSize) {
            return; // 栈已满,按题目要求不执行任何操作
        }
        stack[top] = x;
        inc[top] = 0; // 新元素初始增量为 0
        top++;
    }

    public int pop() {
        if (top == 0) {
            return -1; // 栈为空
        }
        top--;
        int res = stack[top] + inc[top]; // 实际值为元素值加上累积增量
        if (top > 0) {
            inc[top - 1] += inc[top]; // 将增量传递给前一个元素(上浮)
        }
        inc[top] = 0; // 重置当前位的增量
        return res;
    }

    public void increment(int k, int val) {
        if (top == 0) {
            return; // 栈为空,无需操作
        }
        int idx = Math.min(k, top) - 1; // 确定需要增加增量的边界位置
        inc[idx] += val; // 在边界处增加增量
    }
}

示例与解释

假设栈容量为 5,依次执行以下操作:

  1. push(1) → 栈: [1]
  2. push(2) → 栈: [1, 2]
  3. increment(2, 100) → 栈底前 2 个元素各增加 100,但实际只更新 inc[1] = 100
  4. push(3) → 栈: [1, 2, 3]
  5. pop() → 弹出 3(实际值 3 + 0),栈: [1, 2]
  6. pop() → 弹出 2,此时 inc[1] = 100 上浮到 inc[0],实际值 2 + 100 = 102,栈: [1]
  7. pop() → 弹出 1,实际值 1 + 100 = 101,栈空。

关键点

  • increment 操作只更新增量数组,不直接修改栈元素,实现了 O(1) 时间复杂度。
  • pop 时通过增量上浮(inc[top-1] += inc[top])确保增量正确传递。
  • 当栈元素少于 k 个时,Math.min(k, top) 确保不会越界。

复杂度分析

  • 时间复杂度pushpopincrement 均为 O(1)。
  • 空间复杂度:O(n),其中 n 为栈的最大容量,用于存储栈数组和增量数组。

应用场景

这种"惰性增量"技巧适用于需要频繁批量更新前缀或子数组的场景,例如:

  • 数据库中的批量更新操作。
  • 游戏开发中的伤害区域效果(对范围内所有单位增加效果)。
  • 实时数据分析中的滑动窗口统计。

通过延迟计算增量,将本应 O(k) 的操作优化为 O(1),显著提升了性能,尤其在大数据量或高频操作场景下优势明显。

相关推荐
lihongli0001 小时前
关于c++中锁的种类与使用
java·开发语言·c++
hans汉斯1 小时前
基于LSTM与扩展卡尔曼滤波的无人机机载电子磁干扰补偿研究
开发语言·人工智能·算法·目标检测·lstm·人机交互·无人机
赏金术士1 小时前
Kotlin 从入门到进阶 之Lambda & 集合高阶模块(四)
开发语言·windows·kotlin
yingjie1101 小时前
用mcc编译的MATLAB EXE被反编译了?这个工具能帮你加固
开发语言·matlab
Evand J1 小时前
【MATLAB绘图】三维曲面与二维映射组合图绘制,进阶教程与代码示例
开发语言·matlab·绘图
农业工作者1 小时前
IDEA解决springboot工程中Cannot resolve symbol ‘SpringApplication异常 maven解决
java·开发语言·maven
上海合宙LuatOS2 小时前
Air780EPM通过MQTT上传温湿度数据
开发语言·人工智能·物联网·junit·luatos
sheeta19983 小时前
LeetCode 每日一题笔记 日期:2026.05.08 题目:3629. 素数跳跃最小次数
笔记·算法·leetcode
叼烟扛炮3 小时前
C++ 知识点08 类与对象
开发语言·c++·算法·类和对象