[leetcode刷题]——栈和队列

此篇博客主要整理栈和队列的问题。

一、用栈实现队列

232、用栈实现队列   (easy)   2021-01-15

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列的支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾

int pop() 从队列的开头移除并返回元素

int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false

class MyQueue {
    //数据存放在1中,需要取出或者看时转移到2中进行,然后放回1中
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;
    /** Initialize your data structure here. */
    public MyQueue() {
        stack1 = new Stack<Integer>();
        stack2 = new Stack<Integer>();
    }
    
    /** Push element x to the back of queue. */
    public void push(int x) {
        stack1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        while(!stack1.empty()){
            stack2.push(stack1.pop());
        }
        int pop = stack2.pop();
        while(!stack2.empty()){
            stack1.push(stack2.pop());
        }
        return pop;
    }
    
    /** Get the front element. */
    public int peek() {
        while(!stack1.empty()){
            stack2.push(stack1.pop());
        }
        int peek = stack2.peek();
        while(!stack2.empty()){
            stack1.push(stack2.pop());
        }
        return peek;
    }
    
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return stack1.empty();
    }
}

 

二、使用队列来实现栈

225.使用队列来实现栈  (easy) 2021-01-15

使用队列实现栈的下列操作:

push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空

    需要注意的是,Java定义有Stack类,可以new。一共有五个方法,分别是:empty(),peek(),pop(),push(),search()。

  但是java中的Queue定义的是接口interface,不能直接new。实现此接口的有LinkedList等等。此接口有几常用个方法,主要是这三个,add( ), peek( ), pull( ) 。

  

class MyStack {
    //add( ), peek( ), poll( ) 
    private Queue<Integer> queue1;
    private Queue<Integer> queue2;   //1用来存放数据,2用来操作
    /** Initialize your data structure here. */
    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        queue1.add(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        while(queue1.size() > 1){
            queue2.add(queue1.poll());
        }
        int pop = queue1.poll();
        while(!queue2.isEmpty()){
            queue1.add(queue2.poll());
        }
        return pop;
    }
    
    /** Get the top element. */
    public int top() {
        while(queue1.size() > 1){
            queue2.add(queue1.poll());
        }
        int top = queue1.peek();
        queue2.add(queue1.poll());
        while(!queue2.isEmpty()){
            queue1.add(queue2.poll());
        }
        return top;
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue1.isEmpty();
    }
}

 

 

三、最小栈

155、最小栈   (easy)    2021-01-15

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

 

  偷了个懒,使用上一题用队列实现栈,然后调用Collections.min()函数。好家伙,直接时间、内存都是5%,怕了怕了。

  我最初的想法是,设置一个变量记录栈的最小值。但是弹出操作后,有可能会将最小值弹出,然后又得重新遍历整个栈。所以直接用两个队列来存储数据,方便弹出后取最小值。

  力扣评论区真的卧虎藏龙,有位朋友实现了我最初的想法。简单来说就是最小值入栈时将当前最小值也入栈存储,最小值出栈时连出两个元素。

 

  具体来说就是:在入栈的时候,如果是比最小值大,那么直接入栈;如果比最小值还小,那么先将当前最小值(也就是次小值)入栈,然后将此最小值入栈,最小值跟新。在出栈的时候,如果出的不是最小值,那么直接出栈;如果出栈的等于最小值,那么将最小值赋值为栈顶第二个元素(也就是次小值),出栈两个元素。

class MinStack {
    
    private int min = Integer.MAX_VALUE;
    private Stack<Integer> stack;
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
    }

    public void push(int x) {
        if(min >= x){
            stack.push(min);
            min = x;
        }
        stack.push(x);
    }

    public void pop() {
        if(stack.pop() == min){
            min = stack.pop();
        }
    }

    public int top() {
      return stack.peek();
    }

    public int getMin() {
        return min;
    }}

 

 

四、有效的括号

20.有效的括号  (easy) 2021-01-16

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()[]{}"
输出: true

示例 2:

输入: "([)]"
输出: false

 

此题解法:核心思想就是使用栈。左括号入栈,右括号出栈对比。

 

 

class Solution {
    public boolean isValid(String s) {
        char[] arr = s.toCharArray();
        
        Map<Character,Character> map = new HashMap<>();
        map.put('(', ')');
        map.put('{', '}');
        map.put('[', ']');
        Stack<Character> stack = new Stack<>();
        if(arr.length % 2 !=  0){
            return false;
        }
        for(int i = 0; i < arr.length; i++){
            if(arr[i] == '(' || arr[i] == '[' || arr[i] == '{'){
                stack.push(arr[i]);
            }
            if(arr[i] == ')' || arr[i] == ']' || arr[i] == '}'){
                if(stack.empty() || map.get(stack.pop()) != arr[i]){
                    return false;
                }
            }
        }
        if(!stack.empty()){
            return false;
        }
        return true;
    }
}

 

  总能在力扣评论区看到一堆神人。直接循环遍历字符串,每次至少可以去掉一个括号。美中不足就是有点费时费空间。

class Solution {
    public boolean isValid(String s) {
        int length = s.length() / 2;
        for (int i = 0; i < length; i++) {
            s = s.replace("()", "").replace("{}", "").replace("[]", "");
        }
        return s.length() == 0;
    }
}

 

五、数组中元素与下一个比他大的元素之间的距离

739. 每日温度 (medium) 2021-01-16

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

  最无脑的方法就是,双重循环,哈哈,耗时击败5%。

class Solution {
    public int[] dailyTemperatures(int[] T) {
        for(int i = 0 ; i < T.length; i++){
            for(int j = i ; j < T.length; j++){
                if(T[j] > T[i]){
                    T[i] = j -i;
                    break;
                }else{
                    if(j == T.length - 1){
                        T[i] = 0;
                    }
                }
            }
        }
        return T;
    }
}

  一个很妙的算法是,新建一个栈一个数组,从头向后遍历,将数组下标放进栈中,下标对应的数应该是从大到小,如果遍历到比栈顶存储下标对应的元素大,那么比当前数小的全部出栈。栈始终保持栈底最大,栈顶最小。

class Solution {
    public int[] dailyTemperatures(int[] T) {
        LinkedList<Integer> stack = new LinkedList<>();   //一个栈,存放索引
        int[] ans = new int[T.length];     
        stack.push(0);
        for(int i = 1; i < T.length; i++){  
            while(!stack.isEmpty() && T[i] > T[stack.peek()]){
                ans[stack.peek()] = i - stack.pop();
            }
            stack.push(i);  
        }
        return ans;
    }
}

 

六、循环数组中比当前元素大的下一个元素

503. 下一个更大的元素  (medium) 2021-01-16

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

  解法:与上一题类似,都是使用单调栈原理。入栈都是从大到小,碰到比栈顶大的元素,小的出栈大的入栈。始终保持栈底最大栈顶最小。此题循环数组就是遍历两次,第二次只出不进,最后留在栈中的全部赋值-1。

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int len = nums.length;
        int[] ans = new int[len];
        Stack<Integer> stack = new Stack<>();
        for(int i = 0; i < len; i++){
            while(!stack.empty() && nums[i] > nums[stack.peek()]){
                ans[stack.pop()] = nums[i];
            }
            stack.push(i);
        }
        if(!stack.empty()){  //如果栈不为空,再次遍历,只是这次不入栈了
            for(int i = 0; i < len; i++){
                while(!stack.empty() && nums[i] > nums[stack.peek()]){
                    ans[stack.pop()] = nums[i];
                }
            }
        }
        while(!stack.empty()){  //如果还是没空,全部赋值-1
            ans[stack.pop()] = -1;
        }
        return ans;
    }
}

 

 

 

posted @ 2021-01-15 16:59  -野比大雄-  阅读(62)  评论(0)    收藏  举报