面试常见算法4:栈和队列

注:此博客不再更新,所有最新文章将发表在个人独立博客limengting.site。分享技术,记录生活,欢迎大家关注

1、数组/栈/队列间的转换:

1.1 固定数组实现栈结构:

这里写图片描述

package sword_to_offer_stack_queue;

public class UseArrayBuildArrayStack {
    // 固定数组实现栈
    // 准备一个变量index,数组的大小设置为为栈的大小为initSize
    // 当要加一个数,index的含义为如果新来一个数,我把新来的数放在index位置
    // 当用户让我弹出一个数,我弹出的数是index的下面一个数
    // index == size时上一个数下标为size - 1,栈满,如还要压入给用户报错
    // index == 0时上一个数下标为-1.栈空,如还要弹出给用户报错
    public static class ArrayStack {
        private int[] arr;
        private int index;
        public int size;

        public ArrayStack(int initSize) {
            if (initSize < 0) {
                throw new IllegalArgumentException("The init size is less than 0");
            }
            this.size = initSize;
            arr = new int[initSize];
            index = 0;
        }

        public void push(int num) {
            if (index == this.size) {
                throw new ArrayIndexOutOfBoundsException("The ArrayStack is full");
            }
            arr[index++] = num;
        }

        public int pop() {
            if (index == 0) {
                throw new ArrayIndexOutOfBoundsException("The ArrayStack is empty");
            }
            return arr[--index];
        }

        public int peek() {
            if (index == 0) {
                throw new ArrayIndexOutOfBoundsException("The ArrayStack is empty");
            }
            return arr[index - 1];
        }
    }

    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(3);
        arrayStack.push(1);
        arrayStack.push(3);
        arrayStack.push(5);
        //arrayStack.push(7);

        System.out.println("pop(): " + arrayStack.pop());
        System.out.println("pop(): " + arrayStack.pop());
        System.out.println("pop(): " + arrayStack.pop());
        //System.out.println("pop():" + arrayStack.pop());
    }
}

1.2 固定数组实现队列结构:

这里写图片描述

package sword_to_offer_stack_queue;

public class UseArrayBuildArrayQueue {
    // 固定数组实现队列
    // 准备一个变量start变量一个end变量,一开始都指向0位置
    // 再准备一个size变量约束start和end的行为,size表示队列的大小
    // start和end无直接关系(解耦),start或者end都是每次和size比较是否越界
    // end代表当要加一个数,我把新来的数放在end位置
    // start代表当用户让我取出一个数,我取出的数是start位置的数给用户
    // 类似于加数队尾排队打饭,取数队头打完饭走人
    // end一旦到底就返回开头,start一直在追end
    // nonEmptySize == arr.length 时队列为满,如还要加数给用户报错
    // nonEmptySize == 0队列为空,如还要取数给用户报错
    public static class ArrayQueue {
        private int[] arr;
        private int nonEmptySize;
        private int start;
        private int end;

        public ArrayQueue(int initSize) {
            if (initSize < 0) {
                throw new IllegalArgumentException("The init size is less than 0");
            }
            arr = new int[initSize];
            nonEmptySize = 0;
            start = 0;
            end = 0;
        }

        public void add(int num) {
            if (nonEmptySize == arr.length) {
                throw new ArrayIndexOutOfBoundsException("The ArrayQueue is full");
            }
            nonEmptySize++;
            arr[end] = num;
            // end的下一个位置
            end = end == arr.length - 1 ? 0 : end + 1;
        }

        public int poll() {
            if (nonEmptySize == 0) {
                throw new ArrayIndexOutOfBoundsException("The ArrayQueue is empty");
            }
            nonEmptySize--;
            int tmp = start;
            // start的下一个位置
            start = start == arr.length - 1 ? 0 : start + 1;
            return arr[tmp];
        }

        public int peek() {
            if (nonEmptySize == 0) {
                throw new ArrayIndexOutOfBoundsException("The ArrayQueue is empty");
            }
            return arr[start];
        }
    }

    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        arrayQueue.add(1);
        arrayQueue.add(3);
        arrayQueue.add(5);
        //arrayQueue.add(7);

        System.out.println("poll(): " + arrayQueue.poll());
        System.out.println("poll(): " + arrayQueue.poll());
        System.out.println("poll(): " + arrayQueue.poll());
        //System.out.println("poll():" + arrayQueue.poll());
    }
}

1.3 仅用栈结构实现队列结构

package sword_to_offer_stack_queue;

import java.util.Stack;

public class UseStackBuildQueue {
    // 用栈实现队列结构
    // 准备两个栈,一个push栈,一个pop栈
    // 加数据入push栈,取数据从pop栈中拿
    // 总体思路是进push的数据倒入pop栈中,两次逆序等于顺序
    // 倒的两个限制:
    // 1) 如果push开始往pop中倒数据,一次要倒完
    // 2) pop栈不为空,不允许倒数据
    // 只要满足以上两个限制,倒数据的行为可以发生在任何时刻
    public static class TwoStackToQueue {
        private Stack<Integer> stackPush;
        private Stack<Integer> stackPop;

        public TwoStackToQueue() {
            stackPush = new Stack<>();
            stackPop = new Stack<>();
        }

        private void takeOutData() {
            // 2) pop栈不为空,不允许倒数据
            if (!stackPop.isEmpty())
                return;
            // 1) 如果push开始往pop中倒数据,一次要倒完
            while (!stackPush.isEmpty()) {
                stackPop.push(stackPush.pop());
            }
        }

        public void add(int num) {
            stackPush.push(num);
            takeOutData();
        }

        public int poll() {
            if (stackPop.isEmpty() && stackPush.isEmpty()) {
                throw new RuntimeException("Queue is empty");
            }
            takeOutData();
            return stackPop.pop();
        }

        public int peek() {
            if (stackPop.isEmpty() && stackPush.isEmpty()) {
                throw new RuntimeException("Queue is empty");
            }
            takeOutData();
            return stackPop.peek();
        }

    }
    public static void main(String[] args) {
        TwoStackToQueue twoStackToQueue = new TwoStackToQueue();
        twoStackToQueue.add(1);
        twoStackToQueue.add(3);
        twoStackToQueue.add(5);
        //twoStackToQueue.add(7);

        System.out.println("poll(): " + twoStackToQueue.poll());
        System.out.println("poll(): " + twoStackToQueue.poll());
        System.out.println("poll(): " + twoStackToQueue.poll());
        //System.out.println("poll():" + twoStackToQueue.poll());
    }
}

1.4 仅用队列结构实现栈结构

package sword_to_offer_stack_queue;

import java.util.LinkedList;
import java.util.Queue;

public class UseQueueBuildStack {
    // 用队列结构实现栈结构
    // 准备两个队列,一个data队列,一个help队列
    // 压入数入data队列
    // 弹出数将data队列中的数除最后一个其他的压入help队列,将最后一个数返回用户,再将data和help引用互换
    public static class TwoQueueToStack {
        private Queue<Integer> data;
        private Queue<Integer> help;

        public TwoQueueToStack() {
            data = new LinkedList<>();
            help = new LinkedList<>();
        }

        public void push(int num) {
            data.add(num);
        }

        public int pop() {
            if (data.isEmpty()) {
                throw new RuntimeException("Stack is empty");
            }
            while (data.size() > 1) {
                help.add(data.poll());
            }
            int res = data.poll();
            swap();
            return res;
        }

        public int peek() {
            if (data.isEmpty()) {
                throw new RuntimeException("Stack is empty");
            }
            while (data.size() > 1) {
                help.add(data.poll());
            }
            int res = data.poll();
            help.add(res);
            swap();
            return res;
        }


        private void swap() {
            Queue<Integer> tmp = data;
            data = help;
            help = tmp;
        }
    }

    public static void main(String[] args) {
        TwoQueueToStack twoQueueToStack = new TwoQueueToStack();
        twoQueueToStack.push(1);
        twoQueueToStack.push(3);
        twoQueueToStack.push(5);
        //twoQueueToStack.push(7);

        System.out.println("pop(): " + twoQueueToStack.pop());
        System.out.println("pop(): " + twoQueueToStack.pop());
        System.out.println("pop(): " + twoQueueToStack.pop());
        //System.out.println("pop():" + twoQueueToStack.pop());
    }
}

2、添加指定功能修改栈

2.1 实现带getMin()函数的栈

实现一个栈,要求在普通栈的基础上加一个得到所有元素的最小值的函数getMin(),要求时间复杂度O(1)

package sword_to_offer_stack_queue;

import java.util.Stack;

public class GetMinStack {
    // 实现一个栈,要求在普通栈的基础上加一个得到所有元素的最小值的函数getMin(),要求时间复杂度O(1)
    // 准备两个栈,data栈和min栈
    // 数据入data栈的同时,同步将min{min栈栈顶,即将压入data的当前数}压入min栈
    // min栈的栈顶就是所有数中的最小元素,data栈和min栈中同步入栈,同步出栈,保持个数一致
    public static class minStack1 {
        private Stack<Integer> stackData;
        private Stack<Integer> stackMin;

        public minStack1() {
            stackData = new Stack<>();
            stackMin = new Stack<>();
        }

        // 数据入data栈的同时,同步将min{min栈栈顶,即将压入data的当前数}压入min栈
        public void push(int num) {
            if (stackMin.isEmpty()) {
                stackMin.push(num);
            } else if (num < stackMin.peek()) {
                stackMin.push(num);
            } else {
                stackMin.push(stackMin.peek());
            }
            stackData.push(num);
        }

        // 弹栈你弹我也弹
        public int pop() {
            if (stackMin.isEmpty()) {
                throw new RuntimeException("Stack is empty");
            }
            stackMin.pop();
            return stackData.pop();
        }

        public int getMin() {
            if (stackMin.isEmpty()) {
                throw new RuntimeException("Stack is empty");
            }
            return stackMin.peek();
        }

    }

    // 准备两个栈,data栈和min栈
    // 当入栈时只有当当前值比min栈栈顶小的时候才将当前值压入min栈
    // 当出栈时出栈的值和min栈栈顶比较,若相等则把min栈栈顶移除
    // 与minStack1相比节省min相同时的存储空间,每个min只存一份
    public static class minStack2 {
        private Stack<Integer> stackData;
        private Stack<Integer> stackMin;

        public minStack2() {
            stackData = new Stack<>();
            stackMin = new Stack<>();
        }

        public void push(int num) {
            if (stackMin.isEmpty()) {
                stackMin.push(num);
            } else if (num < stackMin.peek()) {
                stackMin.push(num);
            }
            stackData.push(num);
        }

        public int pop() {
            if (stackData.isEmpty()) {
                throw new RuntimeException("Stack is empty");
            }
            if (stackData.peek() == stackMin.peek()) {
                stackMin.pop();
            }
            return stackData.pop();
        }

        public int getMin() {
            if (stackData.isEmpty()) {
                throw new RuntimeException("Stack is empty");
            }
            return stackMin.peek();
        }
    }

    public static void main(String[] args) {
        minStack1 minStack1 = new minStack1();
        minStack1.push(3);
        System.out.println(minStack1.getMin());
        minStack1.push(4);
        System.out.println(minStack1.getMin());
        minStack1.push(1);
        System.out.println(minStack1.getMin());
        System.out.println(minStack1.pop());
        System.out.println(minStack1.getMin());

        System.out.println("=============");

        minStack2 minStack2 = new minStack2();
        minStack2.push(3);
        System.out.println(minStack2.getMin());
        minStack2.push(4);
        System.out.println(minStack2.getMin());
        minStack2.push(1);
        System.out.println(minStack2.getMin());
        System.out.println(minStack2.pop());
        System.out.println(minStack2.getMin());
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值