单链表实现栈结构

最近遇到一种类型的算法题,是实现栈的pop、push、peek等方法的同时,还让实现min取得栈中最小值的功能, 题目最特殊的一点就是,要求时间复杂度为O(1)。

具体的题目如下:

请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。


示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-stack-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

很明显,这种题如果要保证其时间复杂度为O(1),就不能出现遍历操作,我们必须要在入栈的同时就要想办法保证获取到最小值。

后来知道了一种解法,就是通过单链表实现栈结构,给单链表增加一个结点用于存储每次入栈比较后的最小值

既然知道了思路,我们把题解放到尾部 ,先来用单链表把栈结构实现。实现后也许你就明白解题方式了。

话不多说,直接上代码,先写一个简单的栈结构LinkedList,这里先不添加min结点

class LinkedList{
    Object data;//保存每个入栈元素
    LinkedList next;

    public LinkedList(Object data, LinkedList next){
        this.data = data;
        this.next = next;
    }
}

然后实现栈的一些常见操作,先弄个接口,统一定义一下栈的一些常见实现方法。

/**
 * 定义栈接口
 */
public interface IStack<E> {
    boolean isEmpty();//栈是否为空
    boolean isFull();//栈是否已满
    void push(E parm);//入栈
    E pop();//删除栈顶元素
    E peek();//取出栈顶元素
    void display();//遍历打印栈数据
}

明确定义方法后,我们就来具体实现这些方法。

class OperateStack<E> implements IStack<E>{
    //先初始化一个链表头结点,充当栈顶元素
    LinkedList headNode = null;

    @Override
    public boolean isEmpty(){
        if(headNode == null)//如果头结点为空就说明栈空
            return true;
        return false;
    }

    @Override
    public boolean isFull(){
        //单链表实现的栈,可以动态增加,暂时无需考虑长度问题
        throw new RuntimeException("单链表暂时无需设置长度");
    }


    @Override
    public void push(E parm){//这里需要好好理解下
        if(headNode == null)
            headNode = new LinkedList(parm,null);//第一个结点的next结点为null
        else //这一步可以理解为逆序的单链表
            headNode = new LinkedList(parm,headNode);//将nextNode设置为之前的那个结点
    }

    @Override
    public E pop(){
        LinkedList temp = headNode;//将最前面的一个元素保存下来用于返回
        headNode = headNode.next;//移除最前面的一个元素
        return (E) temp.data;
    }

    @Override
    public E peek(){
        return (E) headNode.data;//直接返回最前面的元素即可
    }

    @Override
    public void display(){
        LinkedList temp = headNode;//这里注意不能直接操作headNode,不然就无法继续其它操作了
        while(temp != null){
            System.out.print(temp.data+"\t");
            temp = temp.next;
        }
        System.out.println("");
    }
}

基本的几个操作实现后,我们写个测试类来测试下吧。

public class Test{
    public static void main(String[] args){
        //实例化栈操作类
        OperateStack<Integer> op = new OperateStack<>();

        //栈中添加一些元素
        op.push(10);
        op.push(15);
        op.push(20);
        op.push(25);
        op.push(30);

        //打印栈
        op.display();

        //获取栈顶元素
        System.out.println("当前栈顶元素为:"+op.peek());

        //取出栈顶元素
        System.out.println("当前栈顶元素为:"+op.pop());

        //再次打印当前的栈结构,看看栈顶元素是否已被取出
        op.display();
    }
}

测试结果如下图:

通过上面的操作,我们知道怎样通过单链表来实现一个栈结构了,现在回到那道题,解决起来就很容易了吧。

我们只需要对上面的单链表添加一个额外的结点变量min用于保存当前的最小值即可,然后根据题意补全实现对应的push、pop、min方法即可。

class MinStack {

    LinkedList headNode = null;
    /** initialize your data structure here. */
    public MinStack() {

    }

    public void push(int x) {
        if(headNode == null){
            headNode = new LinkedList(x,x,null);
        }else{//每次入栈比较并更新当前最小值
            headNode = new LinkedList(x,Math.min(x,headNode.min),headNode);
        }
    }

    public void pop() {
        headNode = headNode.next;
    }

    public int top() {
        return headNode.data;
    }

    public int getMin() {//经过push的比较,栈顶的最小值即为最小元素
        return headNode.min;
    }


}
class LinkedList{
    int data;//保存每个入栈元素
    int min;//保存当前元素以及栈中元素中的最小值
    LinkedList next;

    public LinkedList(int data, int min, LinkedList next){
        this.data = data;
        this.min = min;
        this.next = next;
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

注:这题的解题思路也是来源于题目评论区,侵删。

猜你喜欢

转载自blog.csdn.net/c_o_d_e_/article/details/109334498
今日推荐