设计一个有getMin()功能的栈,时间复杂度O(1)

641 阅读2分钟

[TOC]

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

要求

实现一个特殊栈,在实现基本功能之外,再提供返回栈中最小元素的操作。

  • poppushgetMin操作时间复杂度均为O(1)
  • 设计的栈类可以使用现成的栈结构。

思路

在可以使用现成的栈结构基础上,普通的栈push()pop()操作时间复杂度均为O(1),但是在获取整个栈的最小元素却需要遍历整个栈,时间复杂度为O(N)。那么难度就在如何将getMin()函数的时间复杂度从O(N)降低到O(1)。

通过空间换时间的思想,建立一个辅助栈来实现:

  • 数据栈stackData:该栈中存放所有元素,保证入栈push()函数、出栈pop()函数、获取栈顶元素top()函数逻辑正常无误。
  • 辅助栈stackMin:该栈中存放栈stackData中所有非严格降序的元素,并且数据栈stackData中最小元素始终保持对应在辅助栈的栈顶元素,即getMin()函数只需返回辅助栈stackMin栈顶元素。

函数设计

  • push(x)函数:将元素入栈,同时保持辅助栈stackMin元素为非严格降序的。
    • 将元素入数据栈stackData。(stackData.push(x))
    • 如果辅助栈stackMin为空,如果待入栈元素小于或等于辅助栈stackMin中最小值,将其压入辅助栈stackMin。(stackMin.push(x))
  • pop()函数:保持数据栈stackData 和 辅助栈stackMin数据元素一致。
    • 将数据栈元素出栈(stackData.pop())
    • 若出栈元素和辅助栈栈顶元素一致,则将辅助栈栈顶元素也出栈(stackMin.pop())
  • top()返回数据栈栈顶元素。(stackData.peek())
  • getMin() 返回辅助栈栈顶元素。(stackMin.peek())

时间复杂度

  • 时间复杂度O(1):在执行操作push()pop()top()getMin()这几个函数时,时间复杂度均为常数级别。
  • 时间复杂度O(N):假设有N个元素倒叙入栈时,辅助栈最差情况下回存储N个元素,使用O(N)的额外辅助空间。
    • stackData:5、4、3、2、1
    • stackMin:5、4、3、2、1

代码

import java.util.Stack;

/**
 * <p></p>
 *
 * @author chencong
 * @email ccoder.cc | cong.ccoder@gmail.com
 * @date MinStack.java v1.0  2021/8/23 13:41
 */
public class MinStack {

    Stack<Integer> stackData, stackMin;

    public MinStack() {
        this.stackData = new Stack<>();
        this.stackMin = new Stack<>();
    }

    /**
     * 入栈
     * stackMin为空时,此时待入栈数据便是最小
     * stackMin中最小值和待入栈数据比较,如果待入栈数据较小便将其入栈,否则保持不动
     *
     * @param newNum 待入栈数据
     */
    public void push(int newNum) {
        if (stackMin.isEmpty() || newNum <= this.getMin()) {
            stackMin.push(newNum);
        }
        this.stackData.push(newNum);
    }

    /**
     * 获取栈顶元素
     *
     * @return 获取元素
     */
    public int top() {
        return this.stackData.peek();
    }

    /**
     * 出栈
     *
     * @return 出栈元素
     */
    public int pop() {
        int value = this.stackData.pop();
        if (value == this.stackMin.peek()) {
            this.stackMin.pop();
        }
        return value;
    }

    /**
     * 获取最小元素
     *
     * @return 获得数据
     */
    public int getMin() {
        return this.stackMin.peek();
    }
}

单测

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

/**
 * <p></p>
 *
 * @author chencong
 * @email ccoder.cc | cong.ccoder@gmail.com
 * @date MinStackTest.java v1.0  2021/8/23 15:11
 */

public class MinStackTest {

    private static MinStack stack;

    @Test
    public void getMinTest() {
        System.out.println(stack.getMin());
        Assertions.assertEquals(0, stack.getMin());
    }
    @BeforeAll
    public static void createStackDataTest() {
        stack = new MinStack();
        stack.push(4);
        stack.push(3);
        stack.push(1);
        stack.push(5);
        stack.push(0);
        stack.push(2);
    }
}

扩展

  • MinStack中可以扩展实现Comparable,保证除去基本数据类型其余对账均可O(1)获取最小元素。