打卡第一天:删除无效的括号

题目描述

给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。

解题思路

主要是三个部分:

  1. 判断括号是否有效的函数 judge
  2. 找出最大有效括号的左括号数(left)和右括号数(right);
  3. 以回溯的方式(backtrack)删除多余的括号,并用judge验证所得结果是否有效。

判断括号是否有效

private boolean judge(String s){
	Deque<Character> stack = new ArrayDeque<Character>();
	char[] chs = s.toCharArray();
	for(char ch : chs){
		if(ch == '(') 
			stack.push(ch);
		else if(ch == ')') {
			if(stack.isEmpty()) return false;
			else stack.pop();
       }
   }
   if(!stack.isEmpty()) return false;
   return true;
}

最大有效括号的左括号数(left)、右括号数(right)

List<String> list = new ArrayList<String>();
        
// 初始条件下,括号匹配,直接返回
if(judge(s)) {list.add(s);return list;}

Deque<Character> stack = new ArrayDeque<Character>();
int left = 0, right = 0;
char[] chs = s.toCharArray();
// 类似于判断括号是否匹配:统计左括号的个数,right返回的是可以有效匹配的最大右括号数
for(int i=0; i<chs.length; i++){
    if(chs[i] == '(') {stack.push(chs[i]);left++;}
    else if(chs[i] == ')') {
        right++;
        if(stack.isEmpty()) right--;
        else stack.pop();
    }
}
left -= stack.size();  // 有效匹配的最大左括号的个数

回溯

在上一步中已经获得了最终结果中所获得的左右括号数left、right,只需要删除多余的左右括号,所得结果中的左右括号数就和正确结果中的一致,但应该删除哪些位置中的括号呢?在这里是先得到所有结果,然后再用第一步中的judge去验证,验证通过的即为所求,具体如下:

private void backtrack(int j,int left,int right,char[] chs,StringBuilder sb,Set<String> set){
    for(int i=j; i<chs.length; i++){
        if(chs[i] == '(') 
        	if(left>0) {
        		sb.append(chs[i]);
        		left--;
        	} 
        	else continue;
        else if(chs[i] == ')')
        	if(right>0) {
        		sb.append(chs[i]);
        		right--;
        	} 
        	else continue;
        else sb.append(chs[i]);
        backtrack(i+1,left,right,chs,sb,set);
        sb.deleteCharAt(sb.length()-1);
        if(chs[i] == '(') left++; else right++;
    }
    if(left == 0 && right == 0) {
    	System.out.println(sb.toString());
    	if(judge(sb.toString())) set.add(sb.toString());
    }
    	
}

完整代码如下

class Solution {
    public List<String> removeInvalidParentheses(String s) {
        List<String> list = new ArrayList<String>();
        
        // 初始条件下,括号匹配,直接返回
        if(judge(s)) {list.add(s);return list;}
        
        Deque<Character> stack = new ArrayDeque<Character>();
        int left = 0, right = 0;
        char[] chs = s.toCharArray();
        // 类似于判断括号是否匹配:统计左括号的个数,right返回的是可以有效匹配的最大右括号数
        for(int i=0; i<chs.length; i++){
            if(chs[i] == '(') {stack.push(chs[i]);left++;}
            else if(chs[i] == ')') {
                right++;
                if(stack.isEmpty()) right--;
                else stack.pop();
            }
        }
        left -= stack.size();  // 有效匹配的最大左括号的个数
        Set<String> set = new HashSet<String>();
        backtrack(0,left,right,chs,new StringBuilder(),set);
        for(String src : set) list.add(src);
        return list;
    }
    
    // left,right是有效匹配的最大左右括号数
    // 例如,左括号比右括号多一个,就把所有位置的左括号依次删除一个,再将得到的结果进行校验,满足则保存
    // 左括号比右括号多二个,就从所有位置的左括号任选两个删除,并依次遍历所有情况,再将得到的结果进行校验,满足则保存
    private void backtrack(int j,int left,int right,char[] chs,StringBuilder sb,Set<String> set){
        for(int i=j; i<chs.length; i++){
            if(chs[i] == '(') 
            	if(left>0) {
            		sb.append(chs[i]);
            		left--;
            	} 
            	else continue;
            else if(chs[i] == ')')
            	if(right>0) {
            		sb.append(chs[i]);
            		right--;
            	} 
            	else continue;
            else sb.append(chs[i]);
            backtrack(i+1,left,right,chs,sb,set);
            sb.deleteCharAt(sb.length()-1);
            if(chs[i] == '(') left++; else right++;
        }
        if(left == 0 && right == 0) {
        	System.out.println(sb.toString());
        	if(judge(sb.toString())) set.add(sb.toString());
        }
        	
    }
    
    // 判断括号是否正确
    private boolean judge(String s){
        Deque<Character> stack = new ArrayDeque<Character>();
        char[] chs = s.toCharArray();
        for(char ch : chs){
            if(ch == '(') stack.push(ch);
            else if(ch == ')') {
                if(stack.isEmpty()) return false;
                else stack.pop();
            }
        }
        if(!stack.isEmpty()) return false;
        return true;
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值