本文详细解析LeetCode第301题"删除无效括号",这是一道考察DFS和括号匹配的困难难度题目。文章提供了DFS和BFS两种实现方案,包含C#、Python、C++三种语言实现,配有详细的算法分析和性能对比。适合学习深度优先搜索和字符串处理的读者。
核心知识点: DFS、BFS、括号匹配、字符串处理
难度等级: 困难
推荐人群: 具备基础算法知识,想要提升搜索算法和字符串处理能力的开发者
给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。
有效字符串需满足:
输入:s = "()())()"
输出:["(())()","()()()"]
输入:s = "(a)())()"
输出:["(a())()","(a)()()"]
输入:s = ")("
输出:[""]
本题可以使用两种方法来实现:
DFS(深度优先搜索):
BFS(广度优先搜索):
步骤 | 操作 | 状态 | 说明 |
---|---|---|---|
1 | 统计括号 | 计算需删除数量 | 找出多余的左右括号 |
2 | 选择删除位置 | 递归尝试 | 避免重复删除相同括号 |
3 | 验证有效性 | 检查结果 | 确保括号匹配正确 |
4 | 保存结果 | 添加到结果集 | 去重并保存有效解 |
情况 | 左括号数 | 右括号数 | 处理方式 |
---|---|---|---|
平衡 | n | n | 继续处理 |
左多 | n | < n | 删除左括号 |
右多 | n | > n | 删除右括号 |
无效 | < 右括号数 | m | 直接剪枝 |
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;
}
}
}
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
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 | DFS实现,内存占用较大 |
Python | 44 ms | 15.1 MB | BFS实现,性能适中 |
C++ | 0 ms | 7.2 MB | BFS实现,性能最优 |
解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
---|---|---|---|---|
DFS | O(2^n) | O(n) | 实现简单,易于理解 | 可能有重复计算 |
BFS | O(n * 2^n) | O(2^n) | 找到最优解,避免重复 | 空间消耗大 |
算法专题合集 - 查看完整合集
关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第301题。
感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。
如果这篇文章对你有帮助,请:
你的支持是我持续分享的动力!
一起进步:算法学习路上不孤单,欢迎一起交流学习!