leetcode678. 有效的括号字符串

题目描述:

在这里插入图片描述

方法一:双栈模拟+贪心

思路:我们先来看一下基本的栈匹配模板

先简单的去验证 (())序列

  1. 任何左括号 ( 必须有相应的右括号 )
  2. 任何右括号 ) 必须有相应的左括号 (
  3. 左括号 ( 必须在对应的右括号之前 )

由于栈先入后出的存储结构,当我们往栈中添加元素时,相当于在原始序列的右方添加一个元素,每添加一个元素,我们就可以判断他是否具有匹配规则,当假设题目不存在*号时,我们验证 (())序列:

  1. 下标为0的(入栈,stack[0]=(
  2. 下标为1的(入栈,stack[1]=( ,此时栈顶下标为 1,可以用k=2(栈中有两元素,stack[k-1]为栈顶元素)指向栈顶
  3. 下标为2的)入栈之前,判断栈顶元素是否与当前的元素匹配,匹配则不入栈,同时将栈顶元素弹出,k往左移动(k–)
  4. 循环1~3,若k==0成立,说明栈中无元素,全部匹配成功为有效的字符串

当我们的序列中含有*号时,我们依然可以使用栈来做

  1. 同样先选定被匹配的符号,添加进栈中,匹配的符号不进入栈,并将被匹配的字符弹

  2. 特殊的是这里弹出并不一定非得弹出栈顶元素,由于*的多变性,我们优先将 )与 *去匹配,

原因( 贪心思想 ):这是我们最优的判断方式,(因为我们若按此规则匹配出来的结果还不是有效字符串时,那它就一定不是有效字符串,弹出栈顶元素去匹配只满足了一般情况,而用这种方式去匹配,即满足最优判断方式,设想最优判断情况都不满足,其他情况也必定不满足)

  1. 处理完)后,只剩下( 和* 号未处理 ,再一次将栈中剩下元素按照匹配模板比对,但必须满足:(不能在最右边即: ** ( 是不满足的
  2. 若仅剩下*号或栈为空,均满足条件

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;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R5zZHLeu-1640738599135)(C:\Users\jokehe\AppData\Roaming\Typora\typora-user-images\image-20211229082045887.png)]

方法二:贪心思想(最优解)

我们换一种思路,还是简单的去验证 (())序列,不考虑有 *的情况: 左括号的数量与右括号的数量相同即可

那么我们就可以从左往右遍历 , 去维护一个平衡值0,遇见( 将0加一,遇见 )将0减一,遍历一边到最后如果平衡值还是为0,则符合条件,否则不符合

于此题而言: 我们思考*号的引入,到底应该让平衡值加一还是减一呢??,这时候分情况讨论即可

当* 变为(时,平衡量加一,变为)时平衡量减一,那这样的话,平衡量就存在最大最小值

  1. 匹配的左括号数量最大值必须大于等于0(一定要有右括号和它匹配)
  2. 平衡量的最小值为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;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S4tJHgV5-1640738599136)(C:\Users\jokehe\AppData\Roaming\Typora\typora-user-images\image-20211229083408655.png)]

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值