题目描述:
方法一:双栈模拟+贪心
思路:我们先来看一下基本的栈匹配模板,
先简单的去验证 (())序列
- 任何左括号
(
必须有相应的右括号)
。 - 任何右括号
)
必须有相应的左括号(
。 - 左括号
(
必须在对应的右括号之前)
。
由于栈先入后出的存储结构,当我们往栈中添加元素时,相当于在原始序列的右方添加一个元素,每添加一个元素,我们就可以判断他是否具有匹配规则,当假设题目不存在*号时,我们验证 (())序列:
- 下标为0的(入栈,stack[0]=(
- 下标为1的(入栈,stack[1]=( ,此时栈顶下标为 1,可以用k=2(栈中有两元素,stack[k-1]为栈顶元素)指向栈顶
- 下标为2的)入栈之前,判断栈顶元素是否与当前的元素匹配,匹配则不入栈,同时将栈顶元素弹出,k往左移动(k–)
- 循环1~3,若k==0成立,说明栈中无元素,全部匹配成功为有效的字符串
当我们的序列中含有*号时,我们依然可以使用栈来做
-
同样先选定被匹配的符号,添加进栈中,匹配的符号不进入栈,并将被匹配的字符弹
-
特殊的是这里弹出并不一定非得弹出栈顶元素,由于*的多变性,我们优先将 )与 *去匹配,
原因( 贪心思想 ):这是我们最优的判断方式,(因为我们若按此规则匹配出来的结果还不是有效字符串时,那它就一定不是有效字符串,弹出栈顶元素去匹配只满足了一般情况,而用这种方式去匹配,即满足最优判断方式,设想最优判断情况都不满足,其他情况也必定不满足)
- 处理完)后,只剩下( 和* 号未处理 ,再一次将栈中剩下元素按照匹配模板比对,但必须满足:(不能在最右边即: ** ( 是不满足的
- 若仅剩下*号或栈为空,均满足条件
Code:
class Solution {
public static boolean checkValidString(String s) {
int[] stack=new int[s.length()];//存放括号
int[] stack2=new int[s.length()];//存放新栈
int k=0,k2=0;
// 第一步,先将( 和 * 压入栈中,用 )去匹配消去一部分
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
stack[k]=i;//放入栈中
k++;//指向栈顶的指针加一
}else if(s.charAt(i)=='*'){
stack2[k2]=i;//放入栈中
k2++;//指向栈顶的指针加一
}else{//当为 ( 时
if (k!=0){//优先将( 栈中的元素弹出去匹配
k--;//指向栈顶的指针减一 (等价于弹出一个元素)
}else if (k2!=0){
k2--;//其次将( 栈中的元素弹出去匹配
}else{//两个栈均为空匹配失败
return false;
}
}
}
while (k!=0&&k2!=0){
if (stack2[k2-1]>stack[k-1]){//满足*的下标要比(大,不然*无法变成 )去与(匹配
k--;
k2--;
}else {
return false;
}
}
return k==0?true :false;
}
}
方法二:贪心思想(最优解)
我们换一种思路,还是简单的去验证 (())序列,不考虑有 *的情况: 左括号的数量与右括号的数量相同即可
那么我们就可以从左往右遍历 , 去维护一个平衡值0,遇见( 将0加一,遇见 )将0减一,遍历一边到最后如果平衡值还是为0,则符合条件,否则不符合
于此题而言: 我们思考*号的引入,到底应该让平衡值加一还是减一呢??,这时候分情况讨论即可
当* 变为(时,平衡量加一,变为)时平衡量减一,那这样的话,平衡量就存在最大最小值
- 匹配的左括号数量最大值必须大于等于0(一定要有右括号和它匹配)
- 平衡量的最小值为0时,由于*号可以为空,此时已经平衡,无需将平衡量减一
Code:
class Solution {
public static boolean checkValidString(String s) {
int numMax=0;
int numMin=0;
for(char c: s.toCharArray()){
if(c=='('){
numMax++;
numMin++;
}else if(c==')'){
numMax--;
numMin--;
} else{
numMax++;
numMin--;
}
if(numMax<0){
return false;
}
if(numMin<0){
numMin=0;
}
}
return numMin==0;
}
}