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

本文介绍了如何利用栈和递归队列解决LeetCode中的三个问题:有效括号匹配、删除字符串中的相邻重复项以及逆波兰表达式求值。作者详细阐述了解题思路、代码实现以及可能的难点。
摘要由CSDN通过智能技术生成

LeetCode 20 有效的括号

题目链接:20. 有效的括号

本题是栈的经典应用——消消乐。

【解题思路】

仔细分析题意,可以发现本题括号不匹配的场景其实只有三个:左括号多余、括号类型不匹配、右括号多余。

解题突出一个消消乐,我们创建一个栈,当匹配到左括号时,将其对应类型的右括号入栈,当匹配到右括号时,与栈顶元素进行匹配,此时会出现三种情况:

1.遍历完字符串,但是栈不为空;说明左括号没有对应的右括号进行匹配,因此返回false。

2.栈顶元素与当前遍历到的字符不匹配;说明字符串中的括号类型不匹配,因此返回false。

3.还没遍历完,栈就已经空了;说明右括号没有相应的左括号进行匹配,因此返回false。

【代码部分】

java:

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();
    }
}

【疑难点】

1.一定要先判断栈是否为空再判断栈内括号是否匹配!否则可能会在空栈里操作,产生错误!

2.要先判断左括号的各种类型是否被遍历到再判断栈是否为空!否则可能会出现类似“(){}[]”这样的情况导致判断出错!

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

题目链接:1047. 删除字符串中的所有相邻重复项

本题还是消消乐。

【解题思路】

遍历整个字符串,遇见字符后与栈顶匹配:

        1.栈为空——直接将字符入栈。

        2.栈顶字符相同——说明为相同重复字符,将栈内字符出栈。

        3.栈顶字符不同——说明不为相同重复字符,将字符入栈。

【解题步骤】

本题既可以用栈辅助寻找相邻重复项,也可以直接在字符串上操作,然而java中的String并不支持修改,因此无论怎样,都不能在原字符上操作。

解法一

        1.创建一个栈用来匹配与记录遍历的字符;

        2.创建一个字符类变量ch用来接收每次遍历到的字符;

        3.判断栈是否为空(栈顶元素是否与ch相等):
                        栈为空——直接将字符入栈;
                        栈不为空且栈顶字符相同——说明为相同重复字符,将栈顶字符弹出;
                        栈不为空且栈顶字符不同——说明不为相同重复字符,将字符入栈。

        4.创建一个字符串类型变量str来接收栈内字符;

        5.循环将栈内字符传入字符串str中,直到栈为空;

        6.返回字符串str。

解法二

        1.创建一个StringBuilder类型变量res用来修改字符串;

        2.用一个int类型变量top当指针,指向栈顶,初始化为-1。

        3.循环遍历的操作与解法1 相似,但是出栈和入栈有所不同:
                        出栈操作为:StringBuilder.deleteCharAt(top),执行完毕后top需要减一;
                        入栈操作为:StringBuilder.append(ch),执行完毕后top需要加一。

【代码部分】

java解法一:

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;
    }
}

java解法二:

class Solution {
    public String removeDuplicates(String s) {
		//用StringBuffer来修改字符串,速度没有用StringBuilder来得快
		//StringBuffer res = new StringBuffer();
		StringBuilder res = new StringBuilder();
		int top = -1;//用top当做栈顶的指针,指向当前字符串的首字符,栈空时为-1,因此初始化为-1
		for(int i = 0; i < s.length(); i++){
			char ch = s.charAt(i);
			if(top >= 0 && res.charAt(i) == ch){
				res.deleteCharAt(top);
				top --;
			}else{
				res.append(ch);
				top++;
			}
		}
		return res.toString();
    }
}

【疑难点】

1.为什么解法1中栈的初始化要用ArrayDeque而不用LinkList? 
        答:ArrayDeque会比LinkedList在除了删除元素这一点外会快一点。

2.为什么解法2中要用StringBuilder而不用StringBuffer?
        答:用 StringBuilder 来修改字符串,速度更快。

3.为什么解法2中指向栈顶的指针TOP需要初始化为-1?
        答:用top当做栈顶的指针,指向当前字符串的首字符,栈空时为-1,因此初始化为-1。

LeetCode 150 逆波兰表达式求值

题目链接:150. 逆波兰表达式求值

本题的解题思路广义上来看其实和前两题一样,本质上也是消消乐,对于这类“判断两相邻字符操作”的题,用栈往往能轻松解决。

【解题思路】

首先我们得理解逆波兰表达式是什么;

逆波兰表达式是一种后缀表达式,所谓后缀就是指运算符写所有数字后面的表达式。

        采用逆波兰表达式的优点有:

                1.相较于常见的中序表达式,逆波兰表达式去掉括号后表达式无歧义。

                2.逆波兰表达式适合用栈运算,遇到数字则入栈;遇到运算符则取出栈顶两个数字进行运算,将运算之后的结果压入栈中。

【解题步骤】

1.新建一个LinkdeList类型的栈用来记录我们遍历到的元素

2.遍历表达式,判断每个遍历到的元素:

        如果等于数字,则入栈;

        如果等于加减乘除,则取出栈顶两个元素进行运算,得出结果再入栈。

3.将栈顶元素返回,即为结果。

【代码部分】

java:

class Solution {
    public int evalRPN(String[] tokens) {
		Deque <Integer> stack = new LinkedList<>();
		for(String s : tokens){
			if("+".equals(s)){
				stack.push(stack.pop() + stack.pop());
			}else if("-".equals(s)){
				stack.push(-stack.pop() + stack.pop());
			}else if("*".equals(s)){
				stack.push(stack.pop() *  stack.pop());
			}else if("/".equals(s)){
				int temp1 = stack.pop();
				int temp2 = stack.pop();
				stack.push(temp2 / temp1);
			}else{
				stack.push(Integer.valueOf(s));
			}
		}
		return stack.pop();
    }
}

【疑难点】

1.注意在入栈时,记得将元素转换为整形,再进行入栈!

2.注意!“-”和“/”需要特殊处理、——需要将弹出栈的两个元素位置顺序交换一下再进行运算。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值