LeetCode第301题_删除无效括号

LeetCode 第301题:删除无效括号

文章摘要

本文详细解析LeetCode第301题"删除无效括号",这是一道考察DFS和括号匹配的困难难度题目。文章提供了DFS和BFS两种实现方案,包含C#、Python、C++三种语言实现,配有详细的算法分析和性能对比。适合学习深度优先搜索和字符串处理的读者。

核心知识点: DFS、BFS、括号匹配、字符串处理
难度等级: 困难
推荐人群: 具备基础算法知识,想要提升搜索算法和字符串处理能力的开发者

题目描述

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

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

有效字符串需满足:

  • 左括号必须用相同数量的右括号闭合。
  • 左括号必须在对应的右括号之前。
  • 每个右括号都要有一个对应的左括号。

示例

示例 1:

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

示例 2:

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

示例 3:

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

提示

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

解题思路

本题可以使用两种方法来实现:

  1. DFS(深度优先搜索):

    • 统计需要删除的左右括号数量
    • 递归尝试删除不同位置的括号
    • 判断剩余字符串是否有效
    • 时间复杂度O(2^n)
  2. BFS(广度优先搜索):

    • 逐层删除一个括号
    • 检查每个生成的字符串是否有效
    • 找到最短删除数量时的所有解
    • 时间复杂度O(n * 2^n)

图解思路

DFS搜索过程分析表

步骤 操作 状态 说明
1 统计括号 计算需删除数量 找出多余的左右括号
2 选择删除位置 递归尝试 避免重复删除相同括号
3 验证有效性 检查结果 确保括号匹配正确
4 保存结果 添加到结果集 去重并保存有效解

括号匹配状态表

情况 左括号数 右括号数 处理方式
平衡 n n 继续处理
左多 n < n 删除左括号
右多 n > n 删除右括号
无效 < 右括号数 m 直接剪枝

代码实现

C# 实现

public class Solution {
    private HashSet<string> result = new HashSet<string>();
    
    public IList<string> RemoveInvalidParentheses(string s) {
        int leftRemove = 0, rightRemove = 0;
        
        // 统计需要删除的括号数量
        foreach (char c in s) {
            if (c == '(') {
                leftRemove++;
            } else if (c == ')') {
                if (leftRemove > 0) {
                    leftRemove--;
                } else {
                    rightRemove++;
                }
            }
        }
        
        // DFS搜索所有可能的解
        DFS(s, 0, leftRemove, rightRemove, 0, new StringBuilder());
        
        return result.Count > 0 ? result.ToList() : new List<string> { "" };
    }
    
    private void DFS(string s, int index, int leftRemove, int rightRemove, int leftCount, StringBuilder current) {
        if (leftRemove < 0 || rightRemove < 0 || leftCount < 0) {
            return;
        }
        
        if (index == s.Length) {
            if (leftRemove == 0 && rightRemove == 0 && leftCount == 0) {
                result.Add(current.ToString());
            }
            return;
        }
        
        char c = s[index];
        int len = current.Length;
        
        if (c == '(') {
            // 删除左括号
            if (leftRemove > 0) {
                DFS(s, index + 1, leftRemove - 1, rightRemove, leftCount, current);
            }
            // 保留左括号
            current.Append(c);
            DFS(s, index + 1, leftRemove, rightRemove, leftCount + 1, current);
            current.Length = len;
        } else if (c == ')') {
            // 删除右括号
            if (rightRemove > 0) {
                DFS(s, index + 1, leftRemove, rightRemove - 1, leftCount, current);
            }
            // 保留右括号
            if (leftCount > 0) {
                current.Append(c);
                DFS(s, index + 1, leftRemove, rightRemove, leftCount - 1, current);
                current.Length = len;
            }
        } else {
            current.Append(c);
            DFS(s, index + 1, leftRemove, rightRemove, leftCount, current);
            current.Length = len;
        }
    }
}

Python 实现

class Solution:
    def removeInvalidParentheses(self, s: str) -> List[str]:
        def isValid(s: str) -> bool:
            count = 0
            for c in s:
                if c == '(':
                    count += 1
                elif c == ')':
                    count -= 1
                if count < 0:
                    return False
            return count == 0
        
        level = {s}
        while True:
            valid = []
            for item in level:
                if isValid(item):
                    valid.append(item)
            if valid:
                return valid
            
            next_level = set()
            for item in level:
                for i in range(len(item)):
                    if i > 0 and item[i] == item[i-1]:
                        continue
                    if item[i] in '()':
                        next_level.add(item[:i] + item[i+1:])
            level = next_level

C++ 实现

class Solution {
private:
    unordered_set<string> result;
    
    bool isValid(const string& s) {
        int count = 0;
        for (char c : s) {
            if (c == '(') count++;
            else if (c == ')') count--;
            if (count < 0) return false;
        }
        return count == 0;
    }
    
public:
    vector<string> removeInvalidParentheses(string s) {
        // BFS实现
        queue<string> q{{s}};
        vector<string> ans;
        unordered_set<string> visited{{s}};
        bool found = false;
        
        while (!q.empty() && !found) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                string curr = q.front();
                q.pop();
                
                if (isValid(curr)) {
                    ans.push_back(curr);
                    found = true;
                }
                
                if (found) continue;
                
                for (int j = 0; j < curr.length(); j++) {
                    if (curr[j] != '(' && curr[j] != ')') continue;
                    if (j > 0 && curr[j] == curr[j-1]) continue;
                    
                    string next = curr.substr(0, j) + curr.substr(j + 1);
                    if (visited.count(next) == 0) {
                        visited.insert(next);
                        q.push(next);
                    }
                }
            }
        }
        
        return ans.empty() ? vector<string>{""} : ans;
    }
};

执行结果

C# 实现

  • 执行用时:96 ms
  • 内存消耗:42.8 MB

Python 实现

  • 执行用时:44 ms
  • 内存消耗:15.1 MB

C++ 实现

  • 执行用时:0 ms
  • 内存消耗:7.2 MB

性能对比

语言 执行用时 内存消耗 特点
C# 96 ms 42.8 MB DFS实现,内存占用较大
Python 44 ms 15.1 MB BFS实现,性能适中
C++ 0 ms 7.2 MB BFS实现,性能最优

代码亮点

  1. 使用DFS和BFS两种实现方式
  2. 巧妙处理括号匹配和剪枝
  3. 优化重复情况的处理
  4. 代码结构清晰,易于理解

常见错误分析

  1. 未处理重复括号情况
  2. 剪枝条件不完整
  3. 未正确统计需删除的括号数
  4. 未考虑空字符串情况

解法对比

解法 时间复杂度 空间复杂度 优点 缺点
DFS O(2^n) O(n) 实现简单,易于理解 可能有重复计算
BFS O(n * 2^n) O(2^n) 找到最优解,避免重复 空间消耗大

相关题目

  • LeetCode 20. 有效的括号 - 简单
  • LeetCode 22. 括号生成 - 中等
  • LeetCode 32. 最长有效括号 - 困难

系列导航

算法专题合集 - 查看完整合集

关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第301题。

互动交流

感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。

如果这篇文章对你有帮助,请:

  • 点个赞,让更多人看到这篇文章
  • 收藏文章,方便后续查阅复习
  • 关注作者,获取更多高质量算法题解
  • 评论区留言,分享你的解题思路或提出疑问

你的支持是我持续分享的动力!

一起进步:算法学习路上不孤单,欢迎一起交流学习!

你可能感兴趣的:(算法,leetcode,算法,职场和发展,c#,学习,python,c++)