训练营1001|栈与队列系列(互相实现|有效括号|删除相邻重复项)

目录

232.用栈实现队列

225.用队列实现栈

20.有效的括号

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


232.用栈实现队列

 首先如果用栈和队列互相实现的话,都是用两个。并且栈和队列可以互相转化,所以图的深度优先遍历还是广度优先遍历都是可以使用栈和队列实现的。

然后还有一些细节需要care,在pop的时候就要先将stackIn里面的所有数据都倒进stackOut里面,然后pop数出来。

然后如果分多次进数据的话,就要把stackout里面的数先倒出来,再给其进数据,所以对stackOut有一个判空操作

/**
 * 利用两个栈实现队列
 */
class MyQueue {
    private Stack<Integer> stackIn;
    private Stack<Integer> stackOut;

    public MyQueue() {
        stackIn = new Stack<>();
        stackOut = new Stack<>();
    }

    public void push(int x) {
        stackIn.push(x);
    }

    public int pop() {
        if (!stackOut.isEmpty()) {
            return stackOut.pop();
        }
        pushIntoOut();
        return stackOut.pop();
    }

    public int peek() {
        if (!stackOut.isEmpty()) {
            return stackOut.peek();
        }
        pushIntoOut();
        return stackOut.peek();
    }

    public boolean empty() {
        return stackIn.isEmpty() && stackOut.isEmpty();
    }

    public void pushIntoOut() {
        if (stackIn.isEmpty()) {
            return;
        }
        while (!stackIn.isEmpty()) {
            stackOut.push(stackIn.pop());
        }
    }
}

225.用队列实现栈

 队列实现栈,依旧可以用两个去实现。但是如何用单向队列去实现栈呢?这也是在营里对我之前观念的一个改善与优化。

     add        增加一个元索              如果队列已满,则抛出一个IIIegaISlabEepeplian异常
  remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
  element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
  offer       添加一个元素并返回true       如果队列已满,则返回false
  poll         移除并返问队列头部的元素    如果队列为空,则返回null
  peek       返回队列头部的元素             如果队列为空,则返回null
  put         添加一个元素                      如果队列满,则阻塞
  take        移除并返回队列头部的元素     如果队列为空,则阻塞
       drainTo(list)   一次性取出队列所有元素
知识点: remove、element、offer 、poll、peek 其实是属于Queue接口。 

 保持一个队列跟stack出栈顺序相同,故,queue2作为辅助队列,一有元素先放进去,然后将queue1的加在queue2末尾(如果queue1没有元素,则跳过该步骤),将queue1和queue2交换。

 利用两个队列来实现栈

/**
 * 利用两个队列实现栈
 */
class MyStack {
    Queue<Integer> queue1;//queue1保持与stack相同的出栈顺序
    Queue<Integer> queue2;

    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }

    public void push(int x) {
        queue2.offer(x);
        while (!queue1.isEmpty()) {
            queue2.offer(queue1.poll());
        }
        Queue<Integer> temp = new LinkedList<>();
        temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }

    public int pop() {
        return queue1.poll();
    }

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

    public boolean empty() {
        return queue1.isEmpty();
    }
}
Deque 接口继承了 Queue 接口
所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst

用一个队列实现栈

用一个队列,就是将queue2这个辅助队列消失,我们不是每次往queue2里面加然后再换了,直接用queue1,push就是普通的push,而pop每次使用的时候,都去弹queue最后的数,所以将这个数前面的数全部从前面挨个加在队列尾

然后point来到了如果要依次轮换的话,top函数和pop函数的轮换顺序怎么协同。

所以这也是为什么java实现队列可以使用deque的原因

Deque类里面有first和last之分。

/**
 * 利用一个队列实现栈
 */
class MyStack {
    Deque<Integer> queue;

    public MyStack() {
        queue = new ArrayDeque<>();
    }

    public void push(int x) {
        queue.offer(x);
    }

    /**
     * 弹出元素的时候,将最末尾的元素弹出,所以把他前面的元素全部按次序加在queue的末尾
     *
     * @return
     */
    public int pop() {
        temp();
        return queue.pollFirst();
    }

    public int top() {//返回最末尾的元素
        return queue.peekLast();
    }

    public boolean empty() {
        return queue.isEmpty();
    }

    public void temp() {
        int size = queue.size() - 1;
        while (size > 0) {
            queue.offer(queue.peekFirst());
            queue.pollFirst();
            size--;
        }
    }
}

20.有效的括号

使用栈,遇到可以配对的就弹出,如果都放进去了栈不为空的话,返回false。

首先,可以配对这个就有的琢磨,所以需要一个map通过键值对的方式将各种括号存起来。并且左括号去和右括号匹配,压在栈里面就是右括号去找左括号。所以在key和value这个方面要care。

其次,压栈的时候,需要全部压进去,就可以对s里面的字符进行遍历。最后去判断栈是否为空,为空的话就是全部弹出去了。

class Solution {
    /**
     * 有效字符串需满足:
     * 左括号必须用相同类型的右括号闭合。
     * 左括号必须以正确的顺序闭合。
     * 每个右括号都有一个对应的相同类型的左括号
     *
     * @param s
     * @return
     */
    public boolean isValid(String s) {
        if (s.length() == 0 || s == null || s.length() % 2 != 0) {
            return false;
        }
        Stack<Character> stack = new Stack<>();
        HashMap<Character, Character> hashMap = new HashMap<>();
        hashMap.put(']', '[');
        hashMap.put('}', '{');
        hashMap.put(')', '(');
        stack.push(s.charAt(0));
        for (int i = 1; i < s.length(); i++) {
            if (!stack.isEmpty() && stack.peek().equals(hashMap.get(s.charAt(i)))) {
                stack.pop();
                continue;
            }
            stack.push(s.charAt(i));
        }
        return stack.isEmpty();
    }
}

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

个人看到题目之后的反应----->无非就是个重复循环,但是细想之后,如果是循环的话这个循环的跳出条件是什么?单看一趟去重的话是很容易的。那么怎么判断之后字符串里面没有重复如何跳出呢?在一趟去比较之后再有相邻的还是直接move的话,所以感觉循环就是走一遍s。走完s返回stack逆序。

stack要逆序的话这边就可以使用deque。利用first和last来判断

class Solution {
    /**
     * 删除字符串里面的重复项
     *
     * @param s
     * @return
     */
    public String removeDuplicates(String s) {
        Deque<Character> stack = new ArrayDeque<>();
        for (int i = 0; i < s.length(); i++) {
            if (!stack.isEmpty() && stack.peekLast().equals(s.charAt(i))) {
                stack.pollLast();
                continue;
            }
            stack.addLast(s.charAt(i));
        }
        char[] ch = new char[stack.size()];
        int i = 0;
        while (!stack.isEmpty()) {
            ch[i++] = stack.peekFirst();
            stack.pollFirst();
        }
        return new String(ch);
    }
}

掌握deque,以及栈和队列的相互转换方法

2022.10.10补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值