训练营第十天(栈与队列第二部分)

文章讲述了如何使用栈数据结构解决编程问题,包括检查有效括号配对、删除字符串中的相邻重复项以及计算逆波兰表达式的值。作者通过示例和代码演示了错误和修正逻辑,强调了栈在这些问题中的关键作用。
摘要由CSDN通过智能技术生成

训练营第十天(栈与队列第二部分)

20. 有效的括号

力扣题目链接(opens new window)

题目

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

有效字符串需满足:

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

示例 1:

  • 输入: “()”
  • 输出: true

示例 2:

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

示例 3:

  • 输入: “(]”
  • 输出: false

示例 4:

  • 输入: “([)]”
  • 输出: false

示例 5:

  • 输入: “{[]}”
  • 输出: true

解答

思路

用栈来配对是没有错的,每次将左括号对应的右括号压入栈中,这样当出现右括并且与栈顶相同时,就出栈

但是我出现了错误的逻辑,忽略了当刚开始便是右括号的情况,也就是下面的代码,并没有考虑最开始便是右括号的情况

错误代码

//String s = "){"; 出现该情况时会直接进入else,但是此时并没有结束
class Solution {
    public boolean isValid(String s) {
		if (s.length() % 2 != 0)
			return false;
		Stack<Character> stack = new Stack<>();
		for (int i = 0; i < s.length(); i++) {
			char ch = s.charAt(i);
			if (ch == '(')
				stack.push(')');
			else if (ch == '{')
				stack.push('}');
			else if (ch == '[')
				stack.push(']');
			else if (!stack.isEmpty() && ch == stack.peek())
				stack.pop();
			else//或者不相等或者为空
				return stack.isEmpty();
		}
		return stack.isEmpty();
    }
}

正确代码

class Solution {
    public boolean isValid(String s) {
		if (s.length() % 2 != 0)
			return false;
		Stack<Character> stack = new Stack<>();
		for (int i = 0; i < s.length(); i++) {
			char ch = s.charAt(i);
			if (ch == '(')
				stack.push(')');
			else if (ch == '{')
				stack.push('}');
			else if (ch == '[')
				stack.push(']');
			else if (stack.isEmpty() || ch != stack.peek())
				return false;//只要for还在,就不应该出现栈空的情况
			else//相等
				stack.pop();
		}
		return stack.isEmpty();
    }
}

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

力扣题目链接(opens new window)

题目

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

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:

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

提示:

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

解答

思路一

使用栈(比较慢)

class Solution {
    public String removeDuplicates(String s) {
		Stack<Character> stack = new Stack<>();
		for (int i = 0; i < s.length(); i++) {
			if (!stack.isEmpty() && stack.peek() == s.charAt(i))
				stack.pop();
			else//或者stack为空或者不相等
				stack.push(s.charAt(i));
		}
		String str = "";
		//剩余的元素即为不重复的元素
		while (!stack.isEmpty()) {
			str = stack.pop() + str;//因为出栈为倒序
		}
		return str;
    }
}
思路二

使用数组自定义栈(更快)(也可以看成是快慢指针)

class Solution {
    public String removeDuplicates(String s) {
		char[] S = s.toCharArray();
		int top = -1;//栈顶
		for (int i = 0; i < S.length; i++) {
			if (top == -1 || S[top] != S[i])//栈为空或者栈顶元素不匹配
				S[++top] = S[i];
			else
				top--;
		}
		return new String(S, 0, top + 1);
    }
}

top为慢指针,i为快指针

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) {
		Stack<Integer> stack = new Stack<>();
		for (String token : tokens) {
			if (Objects.equals(token, "+")){
				stack.push(stack.pop() + stack.pop());
			}else if (Objects.equals(token, "-")){
				int temp1 = stack.pop();
				int temp2 = stack.pop();
				stack.push(temp2 - temp1);
			}else if (Objects.equals(token, "*")){
				stack.push(stack.pop() * stack.pop());
			}else if (Objects.equals(token, "/")){
				int temp1 = stack.pop();
				int temp2 = stack.pop();
				stack.push(temp2 / temp1);
			}else {
				stack.push(Integer.parseInt(token));
			}
		}
		return stack.pop();
    }
}
使用自定义栈
class Solution {
    public int evalRPN(String[] tokens) {
		int[] stack = new int[(tokens.length + 1) / 2];//一定为奇数
		int index = -1;
		for (String token : tokens) {
			switch (token) {
				case "+":
					index--;
					stack[index] += stack[index + 1];
					break;//除了两个,入了一个
				case "-":
					index--;
					stack[index] -= stack[index + 1];
					break;
				case "*":
					index--;
					stack[index] *= stack[index + 1];
					break;
				case "/":
					index--;
					stack[index] /= stack[index + 1];
					break;
				default:
					index++;
					stack[index] = Integer.parseInt(token);
			}
		}
		return stack[index];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值