leetcode
leetcode 251 ~ 300
删除无效的括号

删除无效的括号

难度:

标签:

题目描述

给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。

返回所有可能的结果。答案可以按 任意顺序 返回。

 

示例 1:

输入:s = "()())()"
输出:["(())()","()()()"]

示例 2:

输入:s = "(a)())()"
输出:["(a())()","(a)()()"]

示例 3:

输入:s = ")("
输出:[""]

 

提示:

  • 1 <= s.length <= 25
  • s 由小写英文字母以及括号 '('')' 组成
  • s 中至多含 20 个括号

代码结果

运行时间: 58 ms, 内存: 16.0 MB


/*
 * 题目思路:
 * 通过使用Java Stream API来简化集合操作。
 * 我们仍然使用BFS来查找最小数量的删除。
 * 我们用流的方式处理队列和集合,避免显式地遍历集合。
 */
 
import java.util.*;
import java.util.stream.Collectors;
 
public class SolutionStream {
    public List<String> removeInvalidParentheses(String s) {
        if (s == null) return new ArrayList<>();
 
        Set<String> visited = new HashSet<>();
        Queue<String> queue = new LinkedList<>();
        List<String> res = new ArrayList<>();
 
        queue.add(s);
        visited.add(s);
        boolean found = false;
 
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<String> level = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                String str = queue.poll();
                if (isValid(str)) {
                    res.add(str);
                    found = true;
                }
                if (found) continue;
                level.add(str);
            }
            if (found) continue;
 
            level.forEach(str -> {
                for (int i = 0; i < str.length(); i++) {
                    if (str.charAt(i) != '(' && str.charAt(i) != ')') continue;
                    String newStr = str.substring(0, i) + str.substring(i + 1);
                    if (visited.add(newStr)) {
                        queue.add(newStr);
                    }
                }
            });
        }
 
        return res;
    }
 
    private boolean isValid(String s) {
        int count = 0;
        for (char c : s.toCharArray()) {
            if (c == '(') count++;
            if (c == ')') {
                if (count == 0) return false;
                count--;
            }
        }
        return count == 0;
    }
}

解释

方法:

这个题解采用深度优先搜索(DFS)的方法来解决删除无效括号的问题。首先,通过遍历字符串,统计需要删除的左括号和右括号的数量。然后,使用DFS递归地尝试删除字符串中的左括号或右括号,直到删除的数量满足要求。在递归过程中,如果当前字符串已经删除了所有需要删除的括号,就判断当前字符串是否有效,如果有效则加入结果集。为了避免重复结果,在递归时跳过连续相同的字符。

时间复杂度:

O(2^n)

空间复杂度:

O(n)

代码细节讲解

🦆
在DFS函数中,参数`open: int`的作用是什么,为什么需要这个参数?
在DFS函数中,`open`参数表示从哪个索引开始遍历字符串以尝试删除括号。这个参数有助于确保在递归过程中不会回到已经处理过的字符位置,从而避免无谓的重复计算和可能的错误。每次递归调用时,`open`设置为当前正在处理的字符的索引,以此确保递归处理的是当前位置之后的字符串部分。
🦆
如何保证在递归过程中避免产生重复的字符串?题解中提到了跳过连续相同的字符,请问这是如何实现的?
在DFS递归中,为了避免生成重复的字符串,算法检查当前字符和前一个字符是否相同,即`if i > open and s[i] == s[i-1]`。如果相同,则跳过当前的递归调用,因为在前一个字符处已经做过相同的删除操作。这样可以有效避免由于连续相同字符的多次删除而产生相同的结果字符串,从而减少重复计算和输出重复的结果。
🦆
函数`isValid`是如何判断一个字符串是否有效?如果字符串含有字母,这种方法是否仍然适用?
函数`isValid`通过遍历字符串,使用一个计数器来跟踪未匹配的`(`数量。对于每个`(`,计数器增加,对于每个`)`,计数器减少。如果在任何点计数器变为负(即出现多余的`)`),则字符串无效。如果遍历结束后计数器为零,则字符串有效。如果字符串中包含字母或其他非括号字符,这种方法依然适用,因为它只计算括号的平衡性,忽略其他字符。
🦆
在实现中,为何要在DFS函数里检查`l + r > len(s) - i`,这一条件具体是为了解决什么问题?
在DFS函数中,`l + r > len(s) - i`这个条件用来判断是否还有足够的字符可以删除。这里`l`和`r`分别是剩余需要删除的左括号和右括号的数量,而`len(s) - i`是当前索引`i`之后的字符数量。如果需要删除的括号总数超过了剩余的字符数,那么就不可能通过进一步删除括号来使字符串有效,因此这个检查可以提前终止无效的递归路径,优化算法效率。

相关问题

有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

 

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

 

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成