题目来源
题目描述
题目解析
题目解析
- 如果没有
*
:用一个变量,遇到左括号,自增1,遇到右括号,如果此时计数器已经为0了,直接返回false,否则自减1,一旦计数器出现了负数,立即返回false,最后还要看变量是否为0即可 - 难点是这里有
*
, 它既可以作为(
,又可以作为)
。问题是它什么时候当做括号来用呢?举个极端例子:*)
:此时*
作为(
)*
:此时*
当左括号,右括号,还是空,*( 都是不对的- 总之:只要
*
在)
的前面,就一定可以消除)
- 算法:
- 用两个stack,分别存放
(
和*
的位置 - 遍历字符串:
- 当遇到
*
时,压入*
栈 - 当遇到
(
时,压入(
栈 - 当遇到
)
时:- 如果leftStack和starStack均为空,返回false
- 如果leftStack不为空,则pop出一个
(
来抵消当前)
,否则从starStack中pop出一个*
来当做(
来抵消)
- 当遇到
- 用两个stack,分别存放
- 遍历结束后,我们希望leftStack中没有多余的
(
;如果有,我们可以尝试用*
来抵消它:- 当star和left均不为空时,进行循环:
- 如果left的栈顶左括号的位置在star的栈顶星号的右边,那么就组成了 *( 模式,直接返回false
- 否则就说明星号可以抵消左括号,各自pop一个元素。
- 最终退出循环后我们看left中是否还有多余的左括号,没有就返回true,否则false
- 当star和left均不为空时,进行循环:
class Solution {
public:
bool checkValidString(string s) {
std::stack<int> left, star;
for (int i = 0; i < s.size(); ++i) {
if(s[i] == '*'){
star.push(i);
}else if(s[i] == '('){
left.push(i);
}else{
if(left.empty() && star.empty()){
return false;
}
if(!left.empty()){
left.pop();
}else{
star.pop();
}
}
}
while (!left.empty() && !star.empty()){
if(left.top() > star.top()){
return false;
}
left.pop();
star.pop();
}
return left.empty();
}
};
思路
正向把所有星号转成左括号,反向把所有星号转成右括号,统计左括号和右括号的数量,只要有一个小于0,说明不匹配,也就不是一个有效字符串
class Solution {
public:
bool checkValidString(string s) {
int left = 0, right = 0, n = s.size();
for (int i = 0; i < n; ++i) {
if (s[i] == '(' || s[i] == '*') ++left;
else --left;
if (left < 0) return false;
}
if (left == 0) return true;
for (int i = n - 1; i >= 0; --i) {
if (s[i] == ')' || s[i] == '*') ++right;
else --right;
if (right < 0) return false;
}
return true;
}
};
暴力
递归三种情况,分别是当星号为空,左括号,或右括号,只要有一种情况返回true,那么就是true了
class Solution {
public:
bool checkValidString(string s) {
return helper(s, 0, 0);
}
bool helper(string s, int start, int cnt) {
if (cnt < 0) return false;
for (int i = start; i < s.size(); ++i) {
if (s[i] == '(') {
++cnt;
} else if (s[i] == ')') {
if (cnt <= 0) return false;
--cnt;
} else {
return helper(s, i + 1, cnt) || helper(s, i + 1, cnt + 1) || helper(s, i + 1, cnt - 1);
}
}
return cnt == 0;
}
};