[特殊字符] LeetCode 做题笔记(二):678. 有效的括号字符串

📝 LeetCode 做题笔记(二):678. 有效的括号字符串

题目链接678. 有效的括号字符串
难度 :中等 | 语言 :Java | 标签:栈、贪心、字符串、动态规划


🔍 题目理解

给定字符串 s,包含 '('')''*' 三种字符,其中 '*' 可视为:

  • 左括号 '('
  • 右括号 ')'
  • 空字符串 ""

判断是否存在一种替换方式,使字符串成为有效括号序列

📌 有效括号规则

  1. 左右括号数量匹配
  2. 任意前缀中,左括号数 ≥ 右括号数

💡 解题思路:贪心 + 区间维护(最优解)

核心洞察

不枚举 * 的所有可能,而是维护未匹配左括号数量的可能范围 [low, high]

状态定义:
  • low:当前最少可能的未匹配左括号数(尽量把 *) 用)
  • high:当前最多可能的未匹配左括号数(尽量把 *( 用)
遍历规则:
字符 low 变化 high 变化 说明
'(' +1 +1 必定增加未匹配左括号
')' -1 -1 必定消耗一个左括号
'*' -1 +1 三种可能:)/(/""
关键剪枝:
java 复制代码
// high < 0:即使把*全当(用,右括号还是太多 → 无效
// low = Math.max(low, 0):未匹配左括号数不能为负(前缀合法性)

🧩 代码实现(贪心法 - Java)

java 复制代码
class Solution {
    public boolean checkValidString(String s) {
        int low = 0, high = 0;
        
        for (char ch : s.toCharArray()) {
            if (ch == '(') {
                low++;
                high++;
            } else if (ch == ')') {
                low = Math.max(low - 1, 0);  // 关键:low不能为负
                high--;
            } else {  // ch == '*'
                low = Math.max(low - 1, 0);  // * 当作 )
                high++;                      // * 当作 (
            }
            
            if (high < 0) {  // 右括号太多,无法匹配
                return false;
            }
        }
        
        return low == 0;  // 最终能否完全匹配
    }
}

🔄 其他解法对比

方法二:双栈法(直观但空间略高)

  • 用两个栈分别记录 '(''*' 的位置
  • 遇到 ')' 优先匹配 '(',没有再匹配 '*'
  • 最后检查剩余 '(' 能否被右侧 '*' 匹配
java 复制代码
class Solution {
    public boolean checkValidString(String s) {
        Deque<Integer> leftStack = new ArrayDeque<>();
        Deque<Integer> starStack = new ArrayDeque<>();
        
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (ch == '(') {
                leftStack.push(i);
            } else if (ch == '*') {
                starStack.push(i);
            } else {  // ')'
                if (!leftStack.isEmpty()) {
                    leftStack.pop();
                } else if (!starStack.isEmpty()) {
                    starStack.pop();
                } else {
                    return false;
                }
            }
        }
        
        // 匹配剩余的 '(',确保 '(' 在 '*' 左侧
        while (!leftStack.isEmpty() && !starStack.isEmpty()) {
            if (leftStack.peek() < starStack.peek()) {
                leftStack.pop();
                starStack.pop();
            } else {
                break;  // '(' 在 '*' 右侧,无法匹配
            }
        }
        
        return leftStack.isEmpty();
    }
}

方法三:动态规划(通用但复杂)

  • dp[i][j] 表示 s[0:i] 是否能形成 j 个未匹配左括号
  • 时间复杂度 O(n²),适合理解但不推荐面试使用
java 复制代码
// 简略版思路,完整实现略长
boolean[][] dp = new boolean[n + 1][n + 1];
dp[0][0] = true;
// 状态转移略...

📊 复杂度分析

方法 时间复杂度 空间复杂度 适用场景
贪心区间 O(n) O(1) ✅ 首选
双栈法 O(n) O(n) 思路直观
动态规划 O(n²) O(n²) 理解状态转移

🎯 总结 & 易错点

贪心法精髓

  • 用区间 [low, high] 表示所有可能状态,避免指数级枚举
  • low = Math.max(low, 0) 是保证前缀合法的关键

常见错误

  1. 忘记 low 不能为负(前缀中右括号不能超过左括号)
  2. 最终判断写成 high == 0(应该是 low == 0,只要有一种可能完全匹配即可)
  3. * 当空字符串的情况被忽略(体现在 low-1high+1 的区间扩展)

💡 举一反三


🔧 Java 特性小贴士

java 复制代码
// 1. TreeSet 自动排序 + 去重
TreeSet<Integer> set = new TreeSet<>();
set.add(3); set.add(1); set.add(2);
// 迭代顺序: 1, 2, 3 (升序)
set.pollFirst();  // 移除并返回最小值
set.pollLast();   // 移除并返回最大值

// 2. Deque 作为栈使用(比 Stack 更高效)
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);      // 入栈
int top = stack.pop();  // 出栈
boolean empty = stack.isEmpty();

// 3. 字符串遍历推荐方式
for (char ch : s.toCharArray()) {  // 简洁
    // ...
}
// 或需要索引时:
for (int i = 0; i < s.length(); i++) {
    char ch = s.charAt(i);
    // ...
}

🌟 写在最后

两道题代表两类典型思维:

  • 1878:几何枚举 + 边界处理 → 锻炼坐标变换能力
  • 678:贪心区间 + 状态压缩 → 培养抽象建模思维

Java 选手注意:

  • TreeSet 是升序,转结果数组时要反转
  • Math.max() 处理边界比三元表达式更清晰
  • 优先用 ArrayDeque 替代 Stack

刷题不在多,而在每道题都吃透核心思想。共勉!🚀

如果这篇笔记对你有帮助,欢迎点赞收藏~ 有其他题想看我写笔记,评论区告诉我!

相关推荐
西岸行者39 分钟前
BF信号是如何多路合一的
算法
大熊背1 小时前
ISP Pipeline中Lv实现方式探究之一
算法·自动白平衡·自动曝光
罗西的思考1 小时前
【OpenClaw】通过 Nanobot 源码学习架构---(5)Context
人工智能·算法·机器学习
Liudef062 小时前
后量子密码学(PQC)深度解析:算法原理、标准进展与软件开发行业的影响
算法·密码学·量子计算
小陈phd2 小时前
多模态大模型学习笔记(三十)—— 基于YOLO26 Pose实现车牌检测
笔记·学习
野指针YZZ3 小时前
XV6操作系统:trap机制学习笔记
笔记·学习
OYpBNTQXi3 小时前
SEAL全同态加密CKKS方案入门详解
算法·机器学习·同态加密
蚂蚁数据AntData4 小时前
破解AI“机器味“困境:HeartBench评测实践详解
大数据·人工智能·算法·机器学习·语言模型·开源
ZC跨境爬虫4 小时前
Python异步IO详解:原理、应用场景与实战指南(高并发爬虫首选)
爬虫·python·算法·自动化
倦王4 小时前
力扣日刷47-补
python·算法·leetcode