有效的括号(括号匹配)
问题叙述
给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
示例 1
输入:s = “()”
输出:true
示例 2:
输入:s = “()[]{}”
输出:true
示例 3:
输入:s = “(]”
输出:false
示例 4:
输入:s = “([)]”
输出:false
示例 5:
输入:s = “{[]}”
输出:true
提示
1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成
分析
栈的先入口处的特点刚好与本题的括号匹配特点一致
如果遇到左括号则入栈,遇到右括号应将对应的栈顶左括号出栈
遍历结束之后,栈为空则符合条件
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| JAVA class Solution { public boolean isValid(String s) { Stack<Character> stack = new Stack(); char ch; for (int i = 0; i < s.length(); i++) { ch = s.charAt(i); if (ch == '[' || ch == '{' || ch == '(') stack.push(ch); else if (ch == '}') { if (stack.isEmpty() || stack.peek() != '{') return false; else stack.pop(); } else if (ch == ']') { if (stack.isEmpty() || stack.peek() != '[') return false; else stack.pop(); } else if (ch == ')') { if (stack.isEmpty() || stack.peek() != '(') return false; else stack.pop(); } } return stack.isEmpty(); } }
class Solution { public boolean isValid(String s) { Stack<Character> stack = new Stack(); char ch; for (int i = 0; i < s.length(); i++) { 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; else stack.pop(); } return stack.isEmpty(); } }
|
删除字符串中所有相邻重复项
来源:力扣(Leetcode)
链接:https://leetcode-cn.com/problems/remove-all-adjacent-duplicates-in-string/
问题叙述
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例
输入:”abbaca”
输出:”ca”
解释
例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。
提示
1 <= S.length <= 20000
S 仅由小写英文字母组成。
分析
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| JAVA class Solution { public String removeDuplicates(String s) { Stack<Character> stack = new Stack<>(); char c; for (int i = 0; i < s.length(); i++) { c = s.charAt(i); if (stack.isEmpty() || stack.peek() != c) stack.push(c); else stack.pop(); } String str = ""; while (!stack.isEmpty()) str = stack.pop() + str; return str; } }
class Solution { public String removeDuplicates(String s) { char[] str = s.toCharArray(); int fast = 0; int slow = -1; for (; fast < str.length; fast++) { if (slow == -1 || str[slow] != str[fast]) str[++slow] = str[fast]; else slow--; } return String.valueOf(str, 0, slow + 1); } }
|
逆波兰表达式求值
来源:力扣(Leetcode)
链接:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
问题叙述
根据 逆波兰表达式,求表达式的值。
有效的算符包括 +、-、、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 *两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1
输入:tokens = [“2”,”1”,”+”,”3”,”“]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) 3) = 9
示例 2
输入:tokens = [“4”,”13”,”5”,”/“,”+”]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3
输入:tokens = [“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 <= tokens.length <= 104
tokens[i] 是一个算符(”+”、”-“、”*” 或 “/“),或是在范围 [-200, 200] 内的一个整数
逆波兰表达式
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
分析
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| JAVA class Solution { public int evalRPN(String[] tokens) { Stack<Integer> stack = new Stack<>(); for (int i = 0; i < tokens.length; i++) { if ("+".equals(tokens[i])) { stack.push(stack.pop() + stack.pop()); } else if ("-".equals(tokens[i])) { stack.push(-stack.pop() + stack.pop()); } else if ("*".equals(tokens[i])) { stack.push(stack.pop() * stack.pop()); } else if ("/".equals(tokens[i])) { int a = stack.pop(); int b = stack.pop(); stack.push(b / a); } else stack.push(Integer.parseInt(tokens[i])); } return stack.peek(); } }
|
滑动窗口的最大值
来源:力扣(Leetcode)
链接:https://leetcode-cn.com/problems/sliding-window-maximum/
问题叙述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值。
示例 1
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
示例 2
输入:nums = [1], k = 1
输出:[1]
提示
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
分析
将每一个元素添加到队列中 只要新元素大于队尾元素(这种情况队尾元素不可能是滑动窗口内的最大值),
那么队尾元素出队,也就是我们维护的是一个单调递减的队列
又由于处在队首的元素是最早进队的,所以我们还需要判断,队首元素是否还在滑动窗口内
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| JAVA class Solution { public int[] maxSlidingWindow(int[] nums, int k) { int[] result = new int[nums.length - k + 1]; LinkedList<Integer> deque = new LinkedList<>(); for (int i = 0; i < nums.length; i++) { while (!deque.isEmpty() && nums[i] >= nums[deque.getLast()]) deque.pollLast(); deque.addLast(i); if (deque.peek() < i - k + 1) deque.poll(); if (i + 1 >= k) result[i + 1 - k] = nums[deque.peek()]; } return result; }
|