代码随想录算法训练营第10天 | 理论基础、232.用栈实现队列、225. 用队列实现栈、20. 有效的括号、1047. 删除字符串中的所有相邻重复项

理论基础

了解一下 栈与队列的内部实现机制,文中是以C++为例讲解的

文章讲解:https://programmercarl.com/%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html

队列(Queue)

队列是一种先进先出(FIFO,First In First Out)的数据结构,元素从队尾加入,从队头取出。Java 提供了多个接口和类来实现队列,例如 Queue 接口和 LinkedList、PriorityQueue 等实现类。

常用操作

  • 添加元素: add(E e) 或 offer(E e)
  • 移除元素: remove() 或 poll()
  • 查看队头元素: element() 或 peek()
栈(Stack)

栈是一种后进先出(LIFO,Last In First Out)的数据结构,元素从栈顶加入,从栈顶取出。Java 提供了 Stack 类来实现栈。

常用操作

  • 压入元素: push(E e)
  • 弹出元素: pop()
  • 查看栈顶元素: peek()
  • 在 Java 中,Stack 是一种容器,它继承自 Vector 类。
  • Java 提供了自己的集合框架(Collections Framework),它与 C++ 的 STL 类似但独立发展。Java 的 Stack 类是从 Java 1.0 版本开始就有的。
  • Stack 类是基于 Vector 实现的,具有动态数组的特性。
  • 虽然 Stack 类没有直接提供迭代器,但它继承自 Vector,因此可以使用 Vector 的迭代器来遍历。

这部分数据结构完全没有学过的印象……准备先打一下基础


232.用栈实现队列

题目链接/文章讲解/视频讲解

图示
class MyQueue {
    Stack<Integer> stackIn;
    Stack<Integer> stackOut;

    public MyQueue() {
        stackIn = new Stack<>();
        stackOut = new Stack<>();
    }
    
    public void push(int x) {
        stackIn.push(x);
    }
    
    public int pop() {
        //只有stackOut为空,才从stackIn导入全部数据
        if(stackOut.isEmpty()){
            while(!stackIn.isEmpty()){
                stackOut.push(stackIn.pop());
            }
        }
        return stackOut.pop();
    }
    
    public int peek() {
        int res = this.pop();
        stackOut.push(res); //因为pop了所以要再添加回去
        return res;
        
    }
    
    public boolean empty() {
        return stackIn.isEmpty() && stackOut.isEmpty();
    }


}

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */

可以注意一下代码是如何复用的。


225. 用队列实现栈

题目链接/文章讲解/视频讲解

一个队列模拟栈的方法
取的是队列里的最后一个元素,就要把之前的size-1个元素添加到队列尾部。


图示
class MyStack {
    Queue<Integer> queue;

    public MyStack() {
        queue = new LinkedList<>();  //注意 initialization
    }
    
    public void push(int x) {
        queue.offer(x);
    }
    
    public int pop() {
        rePosition(); // Queue 接口没有 rePosition 方法。 rePosition 方法是自己在 MyStack 类
                      // 中定义的一个方法,而不是 Queue 接口的一部分。因此,应该直接调用 MyStack 类                    
                      // 中的 rePosition 方法,而不是通过 queue 对象来调用它。
        return queue.poll(); // 弹出最后一个元素,这就是栈顶元素
    }
    
    public int top() {
        rePosition();
        int res = queue.poll();
        queue.offer(res);
        return res;
    }
    
    public boolean empty() {
        return queue.isEmpty();
    }

    private void rePosition(){
        int size = queue.size();
        // 将队列头部的元素(除了最后一个元素外)重新添加到队列尾部
        size--;
        while(size-- > 0){
            queue.offer(queue.poll());
        }
    }
}

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * boolean param_4 = obj.empty();
 */

双端队列不太会,之后补一下学数据结构的笔记。


20. 有效的括号

栈的经典应用了。
题目链接/文章讲解/视频讲解

解题思路

  • 分析不匹配的三种场景:左括号多余;右括号多余;括号数量正确但是不匹配。
  • 如果当前字符是左括号 (、{ 或 [,则将相应的右括号 )、} 或 ] 压入栈中,这样可以直接弹出来检验,方便代码实现
  • 如果当前字符是右括号 )、} 或 ],则进行如下检查:
    如果栈为空(即没有对应的左括号),返回 false。
    如果栈顶的元素与当前字符不匹配,返回 false。
    如果栈顶元素与当前字符匹配,弹出栈顶元素。
    检查栈是否为空:遍历结束后,如果栈为空,说明所有括号都匹配,返回 true;否则,返回 false。
class Solution {
    public boolean isValid(String s) {
        if(s.length() % 2 != 0){
            return false; // 如果s的长度为奇数,一定不符合要求
        }
        Stack<Character> stack = new Stack<>();
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if(c == '('){
                stack.push(')');
            }else if(c == '{'){
                stack.push('}');
            }else if(c == '['){
                stack.push(']');
            }
            // 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号 return false
            // 第二种情况:遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。所以return false
            else if(stack.isEmpty() || stack.peek() != c){
                return false;
            }else{
                stack.pop();
            }

        }
        // 第一种情况:此时我们已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return true
        return stack.isEmpty();
    }
}

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

栈的经典应用。
要知道栈为什么适合做这种类似于爱消除的操作,因为栈帮助我们记录了 遍历数组当前元素时候,前一个元素是什么。
题目链接/文章讲解/视频讲解

解题思路

  • 用栈存遍历过的元素
  • 每遍历一个元素,就检查栈顶元素,相同则弹出元素
  • 直接用字符串来模拟栈,用字符串的尾部作为栈的出口
class Solution {
    public String removeDuplicates(String s) {
        //用字符串作为栈
        StringBuilder res = new StringBuilder();
        for(char c : s.toCharArray()){
            //如果 res 不为空且 res 的最后一个字符与当前字符 c 相不同,则将字符 s 添加到 result 中。
            //否则,删除 result 的最后一个字符。
            if(res.length() > 0 && res.charAt(res.length() -1) == c){
                res.deleteCharAt(res.length() - 1);
            }else{
                res.append(c);
            }
        }
        return res.toString();
    }
}

关于Stringbuilder
StringBuilder是 Java 提供的一个用于创建可变字符串的类。与 String 类不同,StringBuilder 对象可以直接修改其内容,而不是创建新的对象。这使得 StringBuilder 在需要进行大量字符串拼接或修改时更加高效。
特点
可变性:StringBuilder 对象可以被多次修改而不会创建新的对象。
效率高:在需要频繁修改字符串内容的情况下,StringBuilder 的性能要优于 String。
常用方法
以下是一些 StringBuilder 类的常用方法:

方法名 作用
append(String str) 在当前 StringBuilder 对象的末尾添加字符串。
delete(int start, int end) 删除从 start 到 end 索引位置的字符。
deleteCharAt(int index) 删除指定索引位置的字符。
insert(int offset, String str) 在指定位置插入字符串。
reverse() 将当前 StringBuilder 对象中的字符顺序反转。
toString() 将 StringBuilder 对象转换为 String 对象。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容