301.删除无效的括号

该博客探讨了如何确定括号序列的有效性,以及如何通过删除最少的无效括号来确保序列有效。文章提供了两种算法实现,分别采用暴力和优化的方法,通过维护左右括号计数和删除计数来找到最长的有效括号子串,并利用集合避免结果的重复。这两种方法都旨在减少计算量并提高效率。
摘要由CSDN通过智能技术生成

有三个问题需要解决:
1.如何确定是有效状态?
2.如何保证我们获得的是最长的有效括号对(保证我们删除最小数量的无效括号)
3.如何保证结果中的字符串不重复

1.如果一个括号对序列,能保证每一个右括号的左面有大于等于右括号数量的左括号,并且整个括号对序列的数量相同
2.我们使用一个变量minDelete,记录我们删除括号数目的全局最小值,用curDelete记录我们当前结果删除的数量。
3.使用Set去存储结果

第一种方法:暴力
其中numOfLeft和numOfRight分别代表当前使用的左括号和右括号的个数

class Solution {
    int minDelete = Integer.MAX_VALUE;
    StringBuilder sb = new StringBuilder();
    Set<String> res = new HashSet<>();

    public List<String> removeInvalidParentheses(String s) {
        helper(s,0,0,0,0);
        return new ArrayList<>(res);
    }

    public void helper(String s, int index, int numOfLeft, int numOfRight, int curDelete){
        if(index == s.length()){
            if(numOfLeft == numOfRight){
                if(curDelete < minDelete){
                    minDelete = curDelete;
                    res.clear();
                    res.add(sb.toString());
                }
                if(curDelete == minDelete){
                    res.add(sb.toString());
                }
            }
            
        }else if(numOfRight > numOfLeft){
            return;
        }else{
            char c = s.charAt(index);
            if(c != '(' && c != ')'){
                sb.append(c);
                helper(s,index+1,numOfLeft,numOfRight,curDelete);
                sb.deleteCharAt(sb.length()-1);
            }else if(c == '('){
                sb.append(c);
                helper(s,index+1,numOfLeft+1,numOfRight,curDelete);
                sb.deleteCharAt(sb.length()-1);
                helper(s,index+1,numOfLeft,numOfRight,curDelete+1);
            }else{
                sb.append(c);
                helper(s,index+1,numOfLeft,numOfRight+1,curDelete);
                sb.deleteCharAt(sb.length()-1);
                helper(s,index+1,numOfLeft,numOfRight,curDelete+1);
            }
        }
    }
}
}

此方法十分的低效,因为我们尝试删除了每个可能的括号。其中包含了大量无用的遍历。事实上,我们是能知道最优结果的长度,这样我们的计算量就大大减少。根据我之前有效状态的定义,我们可以知道需要删除的左括号和右括号的数量。
如果我们遇到一个左括号,现在并不知道后面有没有右括号去匹配它。我们暂时把它记录成要删除的括号leftDelete+1,后面出现右括号,我们再调整。
如果我们遇到一个右括号,则有两种可能:
1)当leftDelete=0,也就是没有多余的可拿来匹配右括号的左括号,那么rightDelete+1
2)当leftDelete>0,这种情况下只需要leftDelete-1
这里的numOfLeft和numOfRight的定义和上面一样,为了保证有效性。

class Solution {
    StringBuilder sb = new StringBuilder();
    Set<String> res = new HashSet<>();

    public List<String> removeInvalidParentheses(String s) {
        int leftDelete = 0;
        int rightDelete = 0;
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) == '('){
                leftDelete++;
            }else if(s.charAt(i) == ')'){
                rightDelete = leftDelete == 0 ? rightDelete+1 : rightDelete;
                leftDelete = leftDelete > 0 ? leftDelete-1 : leftDelete;
            }
        }
        helper(s, 0, 0, 0, leftDelete, rightDelete);
        return new ArrayList<>(res);
    }

    public void helper(String s, int index, int numOfLeft, int numOfRight, int leftDelete, int rightDelete){
        if(index == s.length()){
            if(leftDelete==0 && rightDelete==0){
                res.add(sb.toString());
            }
        }else if(numOfRight > numOfLeft){
            return;
        }else{
            char c = s.charAt(index);
            if((c == '(' && leftDelete>0) || (c == ')' && rightDelete>0)){
                helper(s, index+1, numOfLeft,numOfRight,leftDelete-(c=='('?1:0),rightDelete-(c==')'?1:0));
            }
            sb.append(c);
            if(c!='(' && c!=')'){
                helper(s,index+1,numOfLeft,numOfRight,leftDelete,rightDelete);
            }else if(c == '('){
                helper(s,index+1,numOfLeft+1,numOfRight,leftDelete,rightDelete);
            }else{
                helper(s,index+1,numOfLeft,numOfRight+1,leftDelete,rightDelete);
            }
            sb.deleteCharAt(sb.length()-1);
        }
    }
}

先不添加,然后考虑添加的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值