发布于个人公众号,打开微信,搜索
MelodyJerry即可
678. 有效的括号字符串
| 难度 | 中等 | 通过率 | 38.36% (40,269/104,970) |
|---|
给定一个只包含三种字符的字符串:( ,) 和 *,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:
- 任何左括号
(必须有相应的右括号)。 - 任何右括号
)必须有相应的左括号(。 - 左括号
(必须在对应的右括号之前)。 *可以被视为单个右括号),或单个左括号(,或一个空字符串。- 一个空字符串也被视为有效字符串。
示例 1:
输入: "()"
输出: True
示例 2:
输入: "(*)"
输出: True
示例 3:
输入: "(*))"
输出: True
注意:
- 字符串大小将在
[1,100]范围内。
题解分析
这是昨天的每日一题,是 LC 《20. 有效的括号》 的进阶,多了个*的干扰。
LC 《20. 有效的括号》 那题可以使用双栈来解决,这题也是可以的,不过需要有些变化。
首先,再来阅读题目描述,注意这点:
*可以被视为单个右括号),或单个左括号(,或一个空字符串。
根绝这点提示,这么看来,我们应该是要优先匹配左括号,既然如此,双栈的策略可以如下这么做:
- 创建双栈
leftStack、starStack,分别存储(、*出现的下标位置; - 遍历字符串
s,若当前遍历的字符为(,当前下标入栈leftStack; - 若当前遍历的字符为
*,当前下标入栈starStack; - 若当前遍历的字符为
),需要分3种情况:- 优先匹配
(,leftStack不空,直接出栈; leftStack为空,但starStack不为空,直接出栈,此时*充当(使用;leftStack为空,且starStack也为空,直接返回false即可;
- 优先匹配
- 遍历完了字符串
s,可能leftStack、starStack中还存留元素:- 尤其是
leftStack不空,那么需要*充当)使用; - 对
leftStack、starStack逐一出栈,得到的是原栈顶的元素,分别表示的(的下标leftIndex、*的下标starIndex; - 需要去比较
leftIndex、starIndex的大小:leftIndex小于starIndex,才能说明(在*的左边,这时候*充当(使用,才会有匹配意义;
- 尤其是
- 最后判断
leftIndex是否为空,为空则说明全部的(和)都匹配完了,返回true; - 其他情况均匹配失败,直接返回
false即可。
以上的双栈策略思路清晰,也方便理解,代码也简单复现。
题解代码
class Solution {
public boolean checkValidString(String s) {
// 用栈记录对应字符出现的下标位置
Stack<Integer> leftStack = new Stack<Integer>();
Stack<Integer> starStack = new Stack<Integer>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '(')
leftStack.push(i);
else if (c == '*')
starStack.push(i);
else if (c == ')') {
// 优先匹配(
if (!leftStack.empty())
leftStack.pop();
else if (!starStack.empty())
starStack.pop();
else
return false;
}
}
while (!leftStack.empty() && !starStack.empty()) {
int leftIndex = leftStack.pop();
int starIndex = starStack.pop();
// 必须是(在*左边
if (leftIndex > starIndex)
return false;
}
return leftStack.empty();
}
}