题目描述

:::fold-green 相关原题

牛客原题: ✅ 【模板】栈

牛客原题没有满栈限制,支持 push、pop、top,空栈读取或出栈输出 error,入栈不输出。本文额外规定固定容量及满栈返回值;用于牛客输入时,可按操作总数分配数组,将 top 对应到 peek,并按题面转换输出。

:::

请使用原生整数数组实现一个容量固定为 capacity 的栈,支持以下操作:

  • push(value):将 value 压入栈顶。成功返回 true;栈已满时不修改栈,返回 false。
  • pop():删除并返回栈顶元素。
  • peek():返回栈顶元素,不修改栈。
  • isEmpty():返回栈是否为空。

空栈调用 pop() 或 peek() 时,Java 返回 null,Go 返回失败标志 (value, false)。

示例 1:

输入: capacity = 2, 操作 = [push(4), push(6), push(8), pop(), peek()]
输出: [true,true,false,6,4]
解释: 第三次入栈时容量已满;出栈得到最后成功入栈的 6,随后栈顶为 4。

提示:

  • capacity≥0,容量固定。
  • 满栈 push 返回 false。
  • 空栈读取或出栈时,Java 返回 null,Go 返回失败标志。

题意分析

栈只在一端插入和删除,数组无需搬移已有元素。用一个有效长度标记栈顶边界,就能在固定容量内完成后进先出操作;容量满和栈为空时必须按题面返回失败。

解法:数组与有效长度模拟固定栈

核心思路

[!blue]

维护不变量 0 <= size <= capacity,有效元素为 values[0..size-1]。size 指向下一次入栈的空位,栈顶是 size - 1,两者不能混用。

入栈先判满,再写入 values[size] 并递增;出栈先判空,再递减 size,读取此时下标处的旧栈顶。peek 只读取 size - 1,不改变有效长度;isEmpty 检查 size == 0。

弹出后数组中遗留的整数不属于有效区间,无需搬移或清零。失败操作必须保持 size 不变,容量为 0 时任何入栈都失败。空栈返回标记与元素值分离,因此整数 0 仍可正常存入。

解题步骤

  1. size 既是有效元素数,也是下一次写入位置。
  2. push 先判满,再写入 values[size] 并增加 size。
  3. pop 先判空,再减少 size 后读取;peek 读取 size-1 但不改变状态。

代码实现

class ArrayStack {
    private final int[] values;
    private int size;

    ArrayStack(int capacity) {
        values = new int[capacity];
    }

    public boolean push(int value) {
        if (size == values.length) {
            return false;
        }

        values[size++] = value;

        return true;
    }

    public Integer pop() {
        return size == 0 ? null : values[--size];
    }

    public Integer peek() {
        return size == 0 ? null : values[size - 1];
    }

    public boolean isEmpty() {
        return size == 0;
    }
}
type ArrayStack struct {
    values []int
    size   int
}

func NewArrayStack(capacity int) *ArrayStack {
    return &ArrayStack{values: make([]int, capacity)}
}

func (s *ArrayStack) Push(value int) bool {
    if s.size == len(s.values) {
        return false
    }
    s.values[s.size] = value
    s.size++
    return true
}

func (s *ArrayStack) Pop() (int, bool) {
    if s.size == 0 {
        return 0, false
    }
    s.size--
    return s.values[s.size], true
}

func (s *ArrayStack) Peek() (int, bool) {
    if s.size == 0 {
        return 0, false
    }
    return s.values[s.size-1], true
}

func (s *ArrayStack) IsEmpty() bool {
    return s.size == 0
}

复杂度分析

  • 时间复杂度:各操作时间 $O(1)$。
  • 空间复杂度:预分配空间 $O(capacity)$。

关键点总结

[!green]

固定容量将扩容搬移排除在操作流程外;空栈与满栈行为是接口约定的一部分。

易错点总结

[!yellow]

size指向下一个空位,栈顶在size-1;这里明确采用定长容量,扩容版本可改为动态数组。

相似题目

题目 难度 关联与区别
补充题 142. 实现动态整数数组 中等 固定容量不扩容,因此 push 最坏常数;动态数组追加只保证均摊常数,扩容当次需要复制。
155. 最小栈 中等 在基础栈操作上增加每层最小值状态,即可扩展为最小栈。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/03266437
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!