栈和队列

栈(Stack)

栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。

常用方法

方法功能
E push(E e)将e入栈,并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素个数
boolean empty()检测栈是否为空

栈,虚拟机栈,栈帧的区别

虚拟机栈栈帧
数据结构JVM的一部分内存调用方法时开辟的内存

逆波兰表达式求值

class Solution {
     public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for(int i = 0;i < tokens.length;i++) {
            String str = tokens[i];
            if(!isOperations(str)) {
                //不是运算符  说明是数字,压入栈
                stack.push(Integer.parseInt(str));
            }else {
                //是运算符
                int num2 = stack.pop();
                int num1 = stack.pop();
                switch(str) {
                    case "+":
                        stack.push(num1+num2);
                        break;
                    case "-":
                        stack.push(num1-num2);
                        break;
                    case "*":
                        stack.push(num1*num2);
                        break;
                    case "/":
                        stack.push(num1/num2);
                        break;
                }
            }
        }
        return stack.pop();
    }
    /*判断当前字符串是不是一个运算符 */
    private boolean isOperations(String str) {
        return (str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/"));
    }
}

有效的括号

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        //1. 遍历字符串
        for(int i = 0;i < s.length();i++) {
            char ch = s.charAt(i);
            //2.是不是左括号
            if(ch == '(' || ch == '[' || ch == '{') {
                stack.push(ch);
            }else {
                //3.右括号
                //3.1 栈为空
                if(stack.isEmpty()) {
                    return false;
                }
                //3.2 栈不为空
                char ch2 = stack.peek();//左括号
                if(ch == ')' && ch2 == '('  || ch == ']'
                        && ch2 == '[' || ch == '}' && ch2 == '{') {
                    stack.pop();
                }else {
                    return false;
                }
            }
        }
        //字符串遍历完了 栈还是不为空
        return stack.isEmpty();
    }
}

最小栈

class MinStack {
    Stack<Integer> stack;
    Stack<Integer> minStack;
    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }
    
    public void push(int val) {
        stack.push(val);
        if(minStack.empty()) {
            minStack.push(val);
        } else {
            int peekNum = minStack.peek();
            if(val<=peekNum) {
                minStack.push(val);
            }
        }
    }
    
    public void pop() {
        int val = stack.pop();
        if(val == minStack.peek()) {
            minStack.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

删除字符串中的所有相邻重复项

用字符串模拟栈

class Solution {
    public String removeDuplicates(String s) {
        StringBuilder ret = new StringBuilder();
        char[] str = s.toCharArray();
        for(char ch: str) {
            if(ret.length() > 0 && ch == ret.charAt(ret.length() - 1)) {
                //出栈
                ret.deleteCharAt(ret.length() - 1);
            } else {
                //进栈
                ret.append(ch);
            }
        }

        return ret.toString();
    }
}

比较含退格的字符串

class Solution {
    public boolean backspaceCompare(String s, String t) {
        return changeStr(s).equals(changeStr(t));
    }

    String changeStr(String str) {
        StringBuilder ret = new StringBuilder();
        for(int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if(ch != '#') {
                //进栈
                ret.append(ch);
            } else {
                //出栈
                if(ret.length() > 0) ret.deleteCharAt(ret.length() - 1);
            }
        }

        return ret.toString();
    }
}

基本计算器II

class Solution {
    public int calculate(String s) {
        Stack<Integer> stack = new Stack<>();
        char op = '+';
        int i = 0, n = s.length();
        char[] str = s.toCharArray();

        while(i < n) {
            if(str[i] == ' ') i++;
            else if(str[i] >= '0' && str[i] <= '9') {
                int tmp = 0;
                while(i < n && str[i] >= '0' && str[i] <= '9') {
                    tmp = tmp * 10 + (str[i] - '0');
                    i++;
                }
                if(op == '+') stack.push(tmp);
                else if(op == '-') stack.push(-tmp);
                else if(op == '*') stack.push(stack.pop() * tmp);
                else stack.push(stack.pop() / tmp);
            } else {
                op = str[i];
                i++;
            }
        } 
        //统计结果
        int ret = 0;
        while(!stack.isEmpty()) {
            ret += stack.pop();
        }
        return ret;
    }
}

字符串解码

class Solution {
    public String decodeString(String s) {
        //先放一个空串
        Stack<StringBuilder> stack = new Stack<>();
        stack.push(new StringBuilder());
        Stack<Integer> nums = new Stack<>();

        int i = 0, n = s.length();
        char[] str = s.toCharArray();

        while(i < n) {
            if(str[i] >= '0' && str[i] <= '9') {
                int tmp = 0;
                while(i < n && str[i] >= '0' && str[i] <= '9') {
                    tmp = tmp * 10 + (str[i] - '0');
                    i++;
                }
                nums.push(tmp);
            } else if(str[i] == '[') {
                i++;//把后面的字符串提取出来
                StringBuilder tmp = new StringBuilder();
                while(i < n && str[i] >= 'a' && str[i] <= 'z') {
                    tmp.append(str[i]);
                    i++;
                }
                stack.push(tmp);
            } else if(str[i] == ']') {
                //解析
                StringBuilder tmp = stack.pop();
                int k = nums.pop();

                while(k-- != 0) {
                    stack.peek().append(tmp);
                } 
                i++;
            } else {
                    StringBuilder tmp = new StringBuilder();
                    while(i < n && str[i] >= 'a' && str[i] <= 'z') {
                        tmp.append(str[i]);
                        i++;
                    }
                    stack.peek().append(tmp);
            }
        }
        return stack.peek().toString();
    }
}

验证栈序列

class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        Stack<Integer> stack = new Stack<>();
        int i = 0, n = popped.length;
        for(int x: pushed) {
            stack.push(x);
            while(!stack.isEmpty() && stack.peek() == popped[i]) {
                stack.pop();
                i++;
            }
        }
        //return i == n;
        return stack.empty();
    }
}

队列(Queue)

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 的原则
入队列:进行插入操作的一端称为队尾(Tail/Rear)
出队列:进行删除操作的一端称为队头(Head/Front)

常用方法

方法功能
boolean offer(E e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()检测队列是否为空

注意:Queue是个接口,要实例化的话必须实例化LinkedList,因为LinkedList实现了Queue接口。

用栈实现队列

class MyQueue {

    private Stack<Integer> s1 ;
    private Stack<Integer> s2 ;

    public MyQueue() {
        s1 = new Stack<>();
        s2 = new Stack<>();
    }
    
    public void push(int x) {
        s1.push(x);
    }
    
    public int pop() {
        if(empty()) {
            return -1;
        }
        if(s2.isEmpty()) {
            //弹出s1当中所有的元素 放到s2中
            while(!s1.isEmpty()) {
                s2.push(s1.pop());
            }
        }
        return s2.pop();
    }
    
    public int peek() {
        if(empty()) {
            return -1;
        }
        if(s2.isEmpty()) {
            //弹出s1当中所有的元素 放到s2中
            while(!s1.isEmpty()) {
                s2.push(s1.pop());
            }
        }
        return s2.peek();
    }
    
    public boolean empty() {
        return s1.isEmpty() && s2.isEmpty();
    }
}

用队列实现栈

两个队列

class MyStack {
    Queue<Integer> queue1;
    Queue<Integer> queue2;

    public MyStack() {
        queue1 = new LinkedList<Integer>();
        queue2 = new LinkedList<Integer>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        queue2.offer(x);
        while (!queue1.isEmpty()) {
            queue2.offer(queue1.poll());
        }
        Queue<Integer> temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue1.poll();
    }
    
    /** Get the top element. */
    public int top() {
        return queue1.peek();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue1.isEmpty();
    }
}

一个队列

class MyStack {
    Queue<Integer> queue;

    /** Initialize your data structure here. */
    public MyStack() {
        queue = new LinkedList<Integer>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        int n = queue.size();
        queue.offer(x);
        for (int i = 0; i < n; i++) {
            queue.offer(queue.poll());
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue.poll();
    }
    
    /** Get the top element. */
    public int top() {
        return queue.peek();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue.isEmpty();
    }
}

设计循环队列

数组(创建时多一个元素)
数组下标循环的小技巧

  • 下标最后再往后: index = (index + offset) % array.length
    在这里插入图片描述

  • 下标最前再往前: index = (index + array.length - offset) % array.length

在这里插入图片描述

当front与rear相等的时候,不知道是为空还是为满
所以front前面的元素不用来存放,front==rear时判空,(rear+1) % elem.length == front为满

class MyCircularQueue {

    public int[] elem;
    public int front;
    public int rear;

    public MyCircularQueue(int k) {
        elem = new int[k+1];
    }

    //入队操作
    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        elem[rear] = value;
        rear = (rear+1) % elem.length;
        return true;
    }
    //删除队头元素
    public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        front = (front + 1) % elem.length;
        return true;
    }
    //得到队头元素 不删除
    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return elem[front];
    }

    //得到队尾元素 不删除
    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        int index = (rear == 0) ? elem.length-1 : rear-1;
        return elem[index];
    }

    //判空 front和rear相遇
    public boolean isEmpty() {
        return front == rear;
    }
    
    public boolean isFull() {
        return (rear+1) % elem.length == front;
    }
}

链表

class MyCircularQueue {
    private ListNode head;
    private ListNode tail;
    private int capacity;
    private int size;

    public MyCircularQueue(int k) {
        capacity = k;
        size = 0;
    }

    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        ListNode node = new ListNode(value);
        if (head == null) {
            head = tail = node;
        } else {
            tail.next = node;
            tail = node;
        }
        size++;
        return true;
    }

    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        head = head.next;  
        size--;
        return true;
    }

    public int Front() {
        if (isEmpty()) {
            return -1;
        }
        return head.val;
    }

    public int Rear() {
        if (isEmpty()) {
            return -1;
        }
        return tail.val;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean isFull() {
        return size == capacity;
    }
}

双端队列 (Deque)

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。
那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值