栈和队列经典的五道面试题------快乐人的java巩固日记[3]

本文深入探讨了栈和队列在编程中的应用,包括括号匹配问题的解决方案、使用栈和队列实现栈、队列以及循环队列。通过实例分析和代码实现,阐述了如何利用栈的先进后出特性解决括号匹配,以及如何借助两个栈或队列实现后入先出的逻辑。此外,还介绍了最小栈的设计,以及如何使用两个栈来模拟循环队列。这些方法展示了数据结构在解决实际问题中的灵活性和效率。
摘要由CSDN通过智能技术生成

栈和队列

第一题 括号匹配问题。

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

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-parentheses
例一

输入:s = “()”
输出:true

例二

输入:s = “()[]{}”
输出:true

例三

输入:s = “(]”
输出:false

这道理我们可以使用栈,为什么呢,栈是采用先进后出的,类似于弹夹一样。我们先让一个括号进去,然后让这个括号和下一个括号,如果这俩组成一个闭合,那么我们就移除栈中的元素放第三个。
我们要分三种基本情况
第一大种类就是对应
第一就是刚好两两对应
如"()","{[]}";我们让他们对应只要循环走完栈就好了。
第二是左边多左边多的花会导致循环走完栈还有元素,我们直接返回false就好。
第三是右边比较多,当字符串遍历到左括号的时候发现栈为空。
第二种为空
直接false。
第三种根本不匹配。
走完栈还有直接false。

class Solution {
    public boolean isValid(String s) {
        if(s==null)
{
    return false;
}
if(s.length()==0){
    return true;
}
Stack<Character>stack=new Stack<>();
for(int i=0;i<s.length();i++){
    char ch=s.charAt(i);
    if(ch=='{'||ch=='('||ch=='['){
        stack.push(ch);
    }else{
        if(stack.empty()){
            System.out.println("右括号多");
            return false;
        }
        char tmp=stack.peek();
        if(tmp=='('&&ch==')'||tmp=='{'&&ch=='}'||tmp=='['&&ch==']'){
                    stack.pop();                
        }else{
            System.out.println("左右括号不一致");
            return false;
        }
         }
        }
        if(!stack.empty()){
            System.out.println("左括多");
            return false;
        }
          return true;
    }
}

第二题队列实现栈。

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-stack-using-queues
**思考:**我们知道栈是先进后出而队列是先进先出,因此我们可以弄两个队列实现栈,比如我们栈里面有1,2,3顺序放入,我们要拿出3可以把12放到另外一个空队列,那么只有一个数的队列就是要出的元素

class MyStack {

    public MyStack() {

    }
    
    public void push(int x) {

    }
    
    public int pop() {

    }
    
    public int top() {

    }
    
    public boolean empty() {

    }
}

以上是要我们实现的方法
public boolean empty()这个比较简单只要返回两个列表都为空即可
public void push(int x) 这个方法就是看哪个是空队列。
public int pop() 这个要判断是否为空,然后

class MyStack {
   private Queue<Integer> qu1=new LinkedList<>();
   private Queue<Integer> qu2=new LinkedList<>();
    public MyStack() {}
    public void push(int x) {
if(!qu1.isEmpty()){
    qu1.offer(x);
}else if(!qu1.isEmpty()){
     qu2.offer(x);
}else{
    qu1.offer(x);
}
    }
    public int pop() {
        if(empty()){
            return -1;
        }
        int e=-1;
if(!qu1.isEmpty()){
    int size=qu1.size();
    for(int i=0;i<size-1;i++){
 e=qu1.poll();
 qu2.offer(e);
    }
    e=qu1.poll();
    }else{
 int size=qu2.size();
    for(int i=0;i<size-1;i++){
 e=qu2.poll();
 qu1.offer(e);
    }
    e=qu2.poll();
    }
 return e;
    }
    public int top() {
         if(empty()){
            return -1;
        }
        int e=-1;
if(!qu1.isEmpty()){
    int size=qu1.size();
    for(int i=0;i<size;i++){
 e=qu1.poll();
 qu2.offer(e);
    }
    }else{
 int size=qu2.size();
    for(int i=0;i<size;i++){
 e=qu2.poll();
 qu1.offer(e);
    }
    }
 return e;
    }
    public boolean empty() {
return qu1.isEmpty()&&qu2.isEmpty();
    }
}

第三题用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-queue-using-stacks

思考我们还是采用上面的方法搞俩栈。一个放1,2,3.然后把3.21.取到第二个队列然后取出第二个队列的头
模板

class MyQueue {

    public MyQueue() {

    }
    
    public void push(int x) {

    }
    
    public int pop() {

    }
    
    public int peek() {

    }
    
    public boolean empty() {

    }
}

做法

class MyQueue {
   private Stack<Integer> sk1;
   private Stack<Integer> sk2;
    public MyQueue() {
        sk1=new Stack<>();
        sk2=new Stack<>();
    }
    public void push(int x) {
            sk1.push(x);
    }
    
    public int pop() {
        if(empty()){
            return -1;
        }
        if(sk2.empty()){
            while(!sk1.empty()){
                sk2.push(sk1.pop());
            }
        }
        return sk2.pop();

    }
    public int peek() {
 if(empty()){
            return -1;
        }
        if(sk2.empty()){
            while(!sk1.empty()){
                sk2.push(sk1.pop());
            }
        }
        return sk2.peek();
    }
    
    public boolean empty() {
        return sk1.empty()&&sk2.empty();

    }
}

第四题 实现一个最小栈

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-stack

输入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.

这个题我们的最小值在发生改变!我们用两个栈一个正常栈一个最小值栈,这样我们pop的时候就简单多了,判断一下等不等就完事了。

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

    }
}

第五题设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/design-circular-queue

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1); // 返回 true
circularQueue.enQueue(2); // 返回 true
circularQueue.enQueue(3); // 返回 true
circularQueue.enQueue(4); // 返回 false,队列已满
circularQueue.Rear(); // 返回 3
circularQueue.isFull(); // 返回 true
circularQueue.deQueue(); // 返回 true
circularQueue.enQueue(4); // 返回 true
circularQueue.Rear(); // 返回 4

在这里插入图片描述

题解
我们可以用环形的队列去理解。我们空出来一个。这样当前后相遇的话一定为空。
我们如果想从7走到0下标可以使用加1然后%本身。就可以。
下面是具体代码实现

class MyCircularQueue {
    private int[] elem;
    private int usedSize;
    private int front;
    private int rear;



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

    }
    
    public boolean enQueue(int value) {
if(isFull()){
    return false;
}
this.elem[this.rear]=value;
this.rear=(this.rear+1)%this.elem.length;
return true;
    }

    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        this.front=(this.front+1)%this.elem.length;
        return true;
    }
    public int Front() {
         if(isEmpty()){
            return -1;
        }
        int val=this.elem[front];
        return val;


    }
    
    public int Rear() {
         if(isEmpty()){
            return -1;
        }
        if(this.rear==0){
            return this.elem[this.elem.length-1];
        }
         return this.elem[this.rear-1];
    }
    
    public boolean isEmpty() {
if(this.front==this.rear){
    return true;
}else{
    return false;
}
    }
    
    public boolean isFull() {
        if((this.rear+1)%this.elem.length==this.front){
            return true;
        }else{
            return false;
        }
    }
}

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卷的快乐人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值