字符串BFS求最少删括号需用map[string]bool层内去重,避免重复入队;合法验证用计数器而非栈以降低开销;同一层生成候选串后须立即查重再入队,否则导致超时或OOM。

字符串 BFS 必须用 map[string]bool 去重,不能靠切片索引
括号删除类问题(如“最少删几个括号使合法”)本质是状态空间搜索:每个字符串是一个节点,删掉一个括号生成新字符串即一条边。BFS 按删除次数分层扩展,首次遇到合法串即得最小步数解。
常见错误是把所有生成的字符串存进切片再遍历,结果同一层反复生成相同串(比如删第1个或第2个右括号得到相同结果),导致爆炸式重复、超时甚至 OOM。
- 必须在每层开始前用
map[string]bool记录本层已入队的所有字符串,if visited[s] { continue } - 不能复用全局
visited——合法解可能来自不同路径,但同一字符串只应入队一次 - 切片无法 O(1) 查重,
for _, v := range queue { if v == s { ... } }是 O(n) 且随层扩大恶化
isParenValid 函数必须用计数器而非栈,避免内存分配
验证单个字符串是否括号合法,高频调用,不能每次 new 一个 slice 或用 stack []rune 模拟。Go 中最轻量的方式是纯整数计数。
错误写法:stack := make([]rune, 0); for _, r := range s { if r == '(' { stack = append(stack, r) } else if r == ')' && len(stack) > 0 { stack = stack[:len(stack)-1] } } —— 分配+扩容开销大,且没处理 count 提前退出
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 正确逻辑:遍历中维护
count int,遇'('加 1,遇')'减 1 - 一旦
count 立刻返回false(右括号多于左括号,不可修复) - 遍历完检查
count == 0,否则左括号过剩 - 跳过非括号字符(字母、数字等),不参与计数
生成下一层候选串时,只删括号,不删字母;且避免重复删同一位置
BFS 扩展规则决定搜索效率。对当前串 s,下一层是所有“删掉恰好一个括号”后的新串。关键约束有三:
- 只删
'('或')',其余字符原样保留 - 同一层内,对相同位置的括号只删一次(哪怕它左右相邻都是
')',也要按索引删,不是按字符删) - 删第 i 个字符后得到
s[:i] + s[i+1:],注意 Go 切片索引不越界:i 范围是0 - 如果上层已删过位置 i,本层仍可删位置 j(j ≠ i),但若多个位置删出相同字符串(如
")()"删第 0 或第 2 个')'都得"()"),靠上层的map[string]bool自动去重
终止条件不是队列空,而是某一层首次出现合法串
题目要求“最少删除数目”,BFS 天然按层数(即删除次数)递增。一旦某层中任意一个字符串通过 isParenValid,就应立即收集所有该层合法串并返回——后续层的解删除更多,直接丢弃。
- 不要等整个队列清空;也不要在发现第一个合法串后立刻
return,因为同层可能有多个不同合法结果(如删不同位置得到不同但都合法的串) - 典型结构:
for len(queue) > 0 { currentLevel := make(map[string]bool); nextQueue := []string{}; for _, s := range queue { if isParenValid(s) { results = append(results, s) } else { for i := range s { if s[i] == '(' || s[i] == ')' { candidate := s[:i] + s[i+1:] if !currentLevel[candidate] { currentLevel[candidate] = true; nextQueue = append(nextQueue, candidate) } } } } }; if len(results) > 0 { return results }; queue = nextQueue } - 如果最终
queue空了还没结果,说明原串无解(理论上不可能,因全删光必合法,但题目隐含至少有一个解)
实际写的时候,最容易被忽略的是:**同一层内去重必须用独立 map,且必须在生成 candidate 后、加入 nextQueue 前立刻检查**。漏掉这个,小输入能过,大数据直接卡死。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










