代码随想录训练营day11

目录

题目一:用栈实现队列

题目二:用队列实现栈

题目三:有效的括号

题目四: 删除字符串中的所有相邻重复项


题目一:用栈实现队列

力扣题目链接

题目描述:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty

思路分析:(来自笨笨在努力

  • 相同的插入顺序,栈与队列的删除顺序正好相反
  • 使用两个栈s1,s2, 其中s1是目标栈,要使s1中元素出栈顺序与队列出队顺序一样,s2是辅助栈,借助s2使s1出栈顺序与队列顺序一样;
  • 添加元素n时,如果s1是空的,直接入s1
  • 否则将s1中的全部元素按出栈顺序插入s2中,直到s1为空,这时,再将n添加进s1,并将s2中的元素依次再添加进s1。
  • 上述过程,借助s2,将s1中元素顺序正好颠倒,使颠倒后的出栈顺序与队列顺序一样

代码:

class MyQueue {

    // 定义两个栈,s1是目标栈,s2是辅助栈
    Stack<Integer> s1;
    Stack<Integer> s2;

    // 构造
    public MyQueue() {
        s1 = new Stack<Integer>();
        s2 = new Stack<Integer>();
    }
    
    // 入队
    public void push(int x) {
        if (s1.isEmpty()) { // 如果s1为空直接入栈
            s1.push(x);
        } else { // 否则将s1中元素全部放入s2中
            while (!s1.isEmpty()) {
                s2.push(s1.pop());
            }
            s1.push(x);
            while (!s2.isEmpty()) { // x入s1后,再将s2中的元素全入s1
                s1.push(s2.pop());
            }
        }
    }
    
    // 出队
    public int pop() {
        return s1.pop();
    }
    
    // 返回队首
    public int peek() {
        return s1.peek();
    }
    
    // 判空
    public boolean empty() {
        return s1.isEmpty();
    }
}

题目二:用队列实现栈

力扣题目链接

题目描述:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty

思路分析:(来自代码随想录

  • 双队列:用两个队列q1和q2实现队列的功能,q2其实完全就是一个备份的作用,把q1最后面的元素以外的元素都备份到q2,然后弹出最后面的元素,再把其他元素从q2导回1
  • 单队列:一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了

解法一:双队列

// 两个队列实现
class MyStack {
    // 定义两个队列q1、q2
    Queue<Integer> q1;
    Queue<Integer> q2;

    // 构造
    public MyStack() {
        q1 = new LinkedList<>();
        q2 = new LinkedList<>();
    }
    
    // 入栈
    public void push(int x) {
        q2.offer(x); // 将元素入辅助队列
        while (!q1.isEmpty()) {
            q2.offer(q1.poll());
        }

        Queue<Integer> temp = q1;
        q1 = q2;
        q2 =temp; // 交换元素,入q2的元素进入q1
    }
    
    // 出栈
    public int pop() {
        return q1.poll();
    }
    

    // 返回栈顶
    public int top() {
        return q1.peek();
    }
    
    // 判空
    public boolean empty() {
        return q1.isEmpty();
    }
}

解法二:单队列

// 一个队列实现
class MyStack {
    // 定义队列q
    Queue<Integer> q;

    // 构造
    public MyStack() {
        q = new LinkedList<>();
    }
    
    // 入栈
    public void push(int x) {
        q.offer(x); // 将元素入队列
        int n = q.size();
        for (int i = 0; i < n - 1; i++) { // 弹出队首元素,并重复加入到队尾
            q.offer(q.poll());
        }
    }
    
    // 出栈
    public int pop() {
        return q.poll();
    }
    

    // 返回栈顶
    public int top() {
        return q.peek();
    }
    
    // 判空
    public boolean empty() {
        return q.isEmpty();
    }
}

 

题目三:有效的括号

力扣题目链接

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

思路分析:(来自代码随想录

  • 第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false

  • 第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false

  • 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false

  • 那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。

代码:

class Solution {
    public boolean isValid(String s) {
        Deque<Character> deque = new LinkedList<>();
        char ch;
        for (int i = 0; i < s.length(); i++) {
            ch = s.charAt(i);
            // 碰到左括号就把相对应的右括号入栈,避免出栈还要进行判断
            if (ch == '(') {
                deque.push(')');
            } else if (ch == '{') {
                deque.push('}');
            } else if (ch == '[') {
                deque.push(']');
            // 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号多了 
            // 第二种情况:遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符,说明对应的括号错了
            } else if (deque.isEmpty() || deque.peek() != ch) { 
                return false;
            } else {
                deque.pop(); // 碰到右括号和栈顶元素匹配时,弹出栈顶元素
            }
        }
        // 第一种情况:此时我们已经遍历完了字符串,但是栈不为空,说明左括号多了
        return deque.isEmpty();
    }
}

题目四: 删除字符串中的所有相邻重复项

力扣题目链接

题目描述:给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。

思路分析:

  • 栈:利用栈的特性,遍历字符串,先存入字母,当栈顶元素与字符串下一个存入的字母相同是弹出栈顶元素
  • 双指针:用fast指针覆盖slow指针的值,遇到相同值,slow指针退一步,fast指针每次循环都前进一步,最后(0,slow)区间内的字母即为最终结果

解法一:栈

class Solution {
    public String removeDuplicates(String s) {
        ArrayDeque<Character> deque = new ArrayDeque<>();

        char ch;
        for (int i = 0; i < s.length(); i++) {
            ch = s.charAt(i);

            if (deque.isEmpty() || deque.peek() != ch) {
                deque.push(ch); // 栈顶元素重复时会被弹出
            } else {
                deque.pop(); // 栈顶元素不重复时加入栈
            }
        }
        String str = "";

        while (!deque.isEmpty()) {
            str = deque.pop() + str; // 将剩余元素弹出
        }
        return str;
    }
}

 解法二:双指针

class Solution {
    public String removeDuplicates(String s) {
        char[] ch = s.toCharArray();
        int fast = 0;
        int slow = 0;
        while (fast < s.length()) {
            // 直接用fast指针覆盖slow指针的值
            ch[slow] = ch[fast];
            // 遇到前后相同值的,就跳过,即slow指针后退一步,下次循环就可以直接被覆盖掉了
            if(slow > 0 && ch[slow] == ch[slow - 1]){
                slow--;
            } else {
                slow++;
            }
            fast++;
        }
        return new String(ch, 0, slow);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值