当前位置: 首页 > 图灵资讯 > 技术篇> 代码随想录算法训练营第十一天|● 20. 有效的括号 ● 1047. 删除字符串中的所有相邻重复项 ● 150. 逆波兰表达式求值

代码随想录算法训练营第十一天|● 20. 有效的括号 ● 1047. 删除字符串中的所有相邻重复项 ● 150. 逆波兰表达式求值

来源:图灵教育
时间:2023-06-05 09:29:26

20. 有效的括号

扣除主题链接(opens new window)

给定一个只包括 字符串,判断字符串是否有效。

需要满足有效字符串:

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

示例 1:

  • 输入: "()"
  • 输出: true

示例2:

  • 输入: ()[]{}”
  • 输出: true

示例3:

  • 输入: "(]"
  • 输出: false

示例4:

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

示例5:

  • 输入: "{[]"""""
  • 输出: true

思路:

没有想法,直接看题解。首先要判断字符串是否有效,需要满足两点:

1、左括号必须与右括号闭合,反之亦然

2、左括号必须以正确的顺序闭合

无效字符串只有三种情况:

1、例如,右括号大于左括号, s = "([])"

2、左括号大于右括号, 比如 s = "([])"

3、顺序不对 ,比如 s = """""""""""""""

采用栈的理念,如果有右括号,则添加相应的左括号;此时,如果左括号遍历,则需要查看栈顶元素是否匹配或为空栈,以便判断情况3和情况2;如果栈顶元素匹配,栈不是空的,把同样的左括号从栈里拿出来。

全部遍历后,还栈还没有空,说明情况1发生了。

class Solution {    public boolean isValid(String s) {        Deque<Character> deq = new LinkedList<>();        char ch ;        for(int i = 0; i < s.length(); i++){            ch = s.charAt(i);            if(ch == '('){                deq.push(')');            }else if(ch == '{'){                deq.push('}');            }else if(ch == '['){                deq.push(']');            }else if(deq.isEmpty() || deq.peek() != ch){    如果下一个不是ch,///deq是空的,说明右方向元素太多。说明顺序不对                return false;            }else{                deq.pop();            }        }        return deq.isEmpty();    }}


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

扣除主题链接(opens new window)

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

在 S 在不能继续删除之前,反复执行重复项删除操作。

删除所有重复项后返回最终字符串。答案是唯一的。

示例:

  • 输入:"abbaca"
  • 输出:"ca"
  • 解释:例如,在 "abbaca" 中间,我们可以删除它 "bb" 由于两个字母相邻且相同,这是此时唯一可以删除的重复项。然后我们得到字符串 "aaca",其中只有 "aa" 重复项的删除操作可以执行,因此最终字符串是 "ca"。

提示:

  • 1 <= S.length <= 20000
  • S 仅由小写英文字母组成。

思路:

一开始,我想使用栈,遍历字符串。如果字符与栈中的字符相同,我会把栈中的字符从栈中走出来,最后留下我们想要的字符串。

后来写的时候发现有三个问题:

1、Deque的用法

Deque是一个双端队列,可以作为栈或队列使用。

一般来说,新的Deque方法是

Deque<Integer> deque = new LinkedList<>();

Deque的许多方法都有重复语义,与Queue或Collection接口兼容

对于队列,入队时从尾部插入元素,出队时从头部插入元素

入队:offer()或者offerlast()

出队:poll() 或者 pollFirst()

查看队首: peek()

针对栈:

入栈:push()

出栈:poll()

栈顶:peek()

2、不能简单地考虑堆栈中的字符和字符串,最好是相邻的

3、最后,如何将栈中的字符输出到字符串中,必须保证顺序不变

class Solution {    public String removeDuplicates(String s) {        Deque<Character> deq = new LinkedList<>();        char ch;        for(int i = 0; i < s.length(); i++){            ch = s.charAt(i);            if(deq.isEmpty() == true || deq.peek() != ch){                deq.push(ch);            }else{                deq.pop();            }                                }        String str = "";        while(!deq.isEmpty()){            str = deq.pop()+str;        }        return str;    }}


150. 逆波兰表达式求值

扣除主题链接(opens new window)

根据 逆波兰表示法,要求表达值。

有效的操作符包括+ , - , * , /.每个计算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

整数除法只保留整数部分。 给定的逆波兰表达式总是有效的。换句话说,表达式总是有效的值,没有除数 0 的情况。

示例1:

  • 输入: ["2", "1", "+", "3", " * "]
  • 输出: 9
  • 解释: 该算法转化为常见的中缀算术表达式:(2) + 1) * 3) = 9

示例2:

  • 输入: ["4", "13", "5", "/", "+"]
  • 输出: 6
  • 解释: 该算法转化为常见的中缀算术表达式:(4 + (13 / 5)) = 6

示例3:

  • 输入: ["10", "6", "9", "3", "+", "-11", " * ", "/", " * ", "17", "+", "5", "+"]
  • 输出: 22
  • 解释:该算法转化为常见的中缀算术表达式:

((10 * (6 / ((9 + 3) * -11))) + 17) + 5       = ((10 * (6 / (12 * -11))) + 17) + 5       = ((10 * (6 / -132)) + 17) + 5     = ((10 * 0) + 17) + 5     = (0 + 17) + 5    = 17 + 5    = 22

逆波兰表达式:它是一种后缀表达式,所谓的后缀是指操作符写在后面。

常用的算法是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。

该算式的逆波兰表达式写法是 ( ( 1 2 + ) ( 3 4 + ) * ) 。

逆波兰表达式主要有以下两个优点:

  • 去除括号后,表达式没有歧义,即使上表达式写成 1 2 + 3 4 + * 正确的结果也可以按顺序计算。
  • 适用于栈操作:遇到数字时进入栈;遇到运算符时,取出栈顶两个数字进行计算,并将结果压入栈中。

思想:

逆波兰表达式相当于后缀表达式,与之前删除的相邻重复项一致,只要有“+”、“-”、“*”、“/”四个字符需要拿出栈中最近两个项目进行操作,然后将操作结果压入栈中。剩下的就是我们想要的结果。

class Solution {    public int evalRPN(String[] tokens) {        Deque<Integer> deq = new LinkedList<>();        for(int i = 0; i < tokens.length; i++){            if("+".equals(tokens[i])){                deq.push(deq.pop()+deq.pop());            }else if("-".equals(tokens[i])){                deq.push(-deq.pop()+deq.pop());            }else if("*".equals(tokens[i])){                deq.push(deq.pop()*deq.pop());            }else if("/".equals(tokens[i])){                int tmp = deq.pop();                int tmp1 = deq.pop();                deq.push(tmp1 / tmp);             }else{                deq.push(Integer.valueOf(tokens[i]));            }        }        return deq.pop();    }}

Integer valueOf(String s):返回指定的保存 String 的值的 Integer 对象。