实现一个支持增量操作的栈
字数 1653 2025-11-14 07:02:29
实现一个支持增量操作的栈
题目描述:设计一个栈,除了支持常规的入栈(push)、出栈(pop)、查看栈顶元素(top)操作外,还需要支持一个增量操作increment(k, val),该操作会将栈底开始的k个元素(即最老的k个元素)都增加val。如果栈中元素个数小于k,则将所有元素都增加val。要求所有操作的时间复杂度为O(1)。
解题思路:
常规栈的push、pop、top操作都是O(1)的,但增量操作如果直接遍历栈底k个元素修改,时间复杂度为O(k),不符合要求。因此,我们需要一种惰性更新的机制,将增量操作延迟到元素被访问(pop或top)时再应用。
核心思想:使用两个栈,一个栈data存储实际元素,另一个栈inc存储增量操作的累积值。inc栈的每个位置对应data栈相同位置的元素从该位置到栈底所有增量操作的总和(但仅在元素被访问时才应用)。
详细步骤:
-
数据结构设计:
data栈:存储实际压入的元素值。inc栈:存储增量操作的累积值,与data栈一一对应。inc[i]表示从栈底到data[i]这个位置,所有增量操作应用到data[i]上的总和(但尚未实际加到data[i]上)。
-
push操作:
- 将新元素压入
data栈。 - 在
inc栈中压入0,表示新元素目前没有累积的增量。
- 将新元素压入
-
increment操作:
- 设当前栈大小为
n,取k = min(k, n)。 - 如果栈非空(
n > 0),将inc栈中第min(k, n) - 1位置(即栈底向上第k个元素在inc栈中的索引)的值增加val。这样,这个增量会随着后续pop操作传播到更靠近栈顶的元素。 - 注意:
inc栈的索引从栈底(0)到栈顶(n-1)。我们只需要在inc[k-1]上累加val,因为当pop到k-1位置时,这个增量会被应用到该元素,并继续向上传播。
- 设当前栈大小为
-
pop操作:
- 如果栈空,返回异常或特定值。
- 弹出
data栈顶元素,记为value。 - 弹出
inc栈顶的累积增量,记为delta(这个delta是当前元素对应的增量)。 - 实际返回值为
value + delta(因为delta包含了所有需要应用到该元素的增量)。 - 如果
inc栈非空,将新的栈顶元素的累积增量加上delta(将增量传播到下一个元素)。
-
top操作:
- 类似pop,但不弹出元素。返回
data.top() + inc.top()。
- 类似pop,但不弹出元素。返回
举例说明:
- 初始化:
data = [],inc = [] - push(1):
data = [1],inc = [0] - push(2):
data = [1, 2],inc = [0, 0] - increment(2, 100): k=2, n=2, 修改
inc[2-1]=inc[1],增加100 →inc = [0, 100] - increment(1, 50): k=1, n=2, 修改
inc[1-1]=inc[0],增加50 →inc = [50, 100] - pop():
value = data.pop() = 2,delta = inc.pop() = 100- 返回值 = 2 + 100 = 102
- 传播增量:
inc栈顶原为50,现在变为50 + 100 = 150 →inc = [150] - 此时
data = [1],inc = [150]
- top(): 返回
data.top() + inc.top() = 1 + 150 = 151 - pop():
value = 1,delta = 150- 返回值 = 1 + 150 = 151
- 栈空,无需传播
通过这种惰性更新机制,所有操作的时间复杂度都是O(1),符合题目要求。增量操作被延迟到元素被访问时才实际计算,避免了遍历修改的开销。