当前位置: 首页 > news >正文

每日一题-力扣-2116. 判断括号字符串是否可以变为有效-20250323

四种解法探究:判断括号字符串是否可以变为有效

在这里插入图片描述

引言

在算法编程中,括号匹配问题是一个经典的字符串处理问题。本文将探讨一个扩展版本:给定一个括号字符串和一个锁定状态字符串,判断是否可以通过修改未锁定的字符,使整个字符串变成有效的括号序列。这个问题不仅测试了对数据结构的理解,也考验了算法设计的灵活性和效率。

问题定义

有两个输入字符串:

  • 括号字符串 s,包含 ‘(’ 和 ‘)’ 字符
  • 锁定状态字符串 locked,包含 ‘0’ 和 ‘1’ 字符

如果 locked[i] 为 ‘1’,则 s[i] 不可修改;如果为 ‘0’,则可以将 s[i] 修改为 ‘(’ 或 ‘)’。需要判断是否可以通过修改未锁定的字符,使最终字符串成为有效的括号序列。

有效的括号序列需满足两个条件:

  1. 左右括号数量相等
  2. 任意前缀中,左括号数量不少于右括号数量

解法一:双向扫描法

双向扫描法通过两次线性扫描来确保括号序列的有效性,充分利用了括号匹配的特性。

原理

  1. 从左到右扫描,确保右括号不会过多
  2. 从右到左扫描,确保左括号不会过多
  3. 如果两次扫描都通过,则序列可以变为有效

实现代码

class Solution:
    def canBeValid(self, s: str, locked: str) -> bool:
        if len(s) % 2:  # 奇数长度直接返回False
            return False
            
        # 简化的双向扫描
        def check(s, locked, open_char):
            balance = 0
            wild = 0  # 未锁定字符数量
            
            # 根据扫描方向调整遍历
            indices = range(len(s)) if open_char == '(' else range(len(s)-1, -1, -1)
            
            for i in indices:
                if locked[i] == '0':
                    wild += 1
                elif s[i] == open_char:
                    balance += 1
                else:
                    balance -= 1
                
                # 关键优化:提前退出条件
                if wild + balance < 0:
                    return False
            
            return True
        
        # 一次调用检查左括号平衡,一次检查右括号平衡
        return check(s, locked, '(') and check(s, locked, ')')

优势

  • 实现简单直观
  • 空间复杂度低,只需常数额外空间
  • 能有效处理边缘情况,如字符串开头的锁定右括号

解法二:贪心算法

贪心算法尝试优先处理当前位置的括号匹配,灵活调整未锁定的字符。

原理

  1. 使用栈来跟踪需要匹配的左括号
  2. 使用一个数组记录未锁定的字符位置
  3. 先从左到右匹配所有右括号,再从右到左匹配所有左括号

实现代码

class Solution:
    def canBeValid(self, s: str, locked: str) -> bool:
        if len(s) % 2 != 0:
            return False
            
        n = len(s)
        available_positions = []  # 存储可修改的位置
        stack = []  # 存储需要匹配的左括号位置
        
        # 第一遍:尝试匹配所有右括号
        for i in range(n):
            if locked[i] == '0':
                available_positions.append(i)
            elif s[i] == '(':
                stack.append(i)
            elif s[i] == ')':
                if stack:  # 有左括号可匹配
                    stack.pop()
                elif available_positions:  # 使用未锁定位置作为左括号
                    available_positions.pop()
                else:
                    return False
        
        # 第二遍:处理多余的左括号
        available_positions = []  # 重置
        stack = []  # 重置
        
        for i in range(n-1, -1, -1):
            if locked[i] == '0':
                available_positions.append(i)
            elif s[i] == ')':
                stack.append(i)
            elif s[i] == '(':
                if stack:  # 有右括号可匹配
                    stack.pop()
                elif available_positions:  # 使用未锁定位置作为右括号
                    available_positions.pop()
                else:
                    return False
        
        return True

优势

  • 显式跟踪括号匹配过程
  • 适用于需要知道具体如何修改字符的场景
  • 提供了括号匹配问题的一种新视角

解法三:平衡范围计算法

平衡范围计算法跟踪每个位置可能的平衡值范围,确保有效的括号序列。

原理

  1. 维护最小和最大可能的平衡值
  2. 对于未锁定字符,考虑将其变为左括号或右括号的影响
  3. 确保最大平衡值不为负,最终最小平衡值为零

实现代码

class Solution:
    def canBeValid(self, s: str, locked: str) -> bool:
        if len(s) % 2 != 0:
            return False
            
        n = len(s)
        min_balance = 0  # 最小可能的平衡值
        max_balance = 0  # 最大可能的平衡值
        
        for i in range(n):
            if locked[i] == '1':
                if s[i] == '(':
                    min_balance += 1
                    max_balance += 1
                else:  # s[i] == ')'
                    min_balance -= 1
                    max_balance -= 1
            else:  # 未锁定字符
                min_balance -= 1  # 假设是右括号
                max_balance += 1  # 假设是左括号
            
            if max_balance < 0:  # 即使全部变为左括号也无法平衡
                return False
                
            min_balance = max(0, min_balance)  # 平衡值不能为负
        
        return min_balance == 0  # 最终必须能达到平衡

优势

  • 使用范围思想,考虑所有可能性
  • 避免了多次扫描
  • 更直观地表示了问题的数学本质

解法四:改进的计数分析法

计数分析法通过精确地分析字符计数和平衡状态,确保有效性判断的准确性。

原理

  1. 结合双向扫描的思想
  2. 实时跟踪平衡状态和可用的未锁定字符
  3. 在每个位置检查平衡状态是否可维持

实现代码

class Solution:
    def canBeValid(self, s: str, locked: str) -> bool:
        # 基础检查:字符串长度必须为偶数
        if len(s) % 2 != 0:
            return False
            
        n = len(s)
        
        # 从左到右扫描:确保右括号不会过多
        balance = 0
        available = 0
        
        for i in range(n):
            if locked[i] == '0':
                available += 1
            elif s[i] == '(':
                balance += 1
            else:  # 锁定的右括号
                balance -= 1
            
            # 关键检查点
            if balance + available < 0:
                return False
        
        # 从右到左扫描:确保左括号不会过多
        balance = 0
        available = 0
        
        for i in range(n-1, -1, -1):
            if locked[i] == '0':
                available += 1
            elif s[i] == ')':
                balance += 1
            else:  # 锁定的左括号
                balance -= 1
            
            if balance + available < 0:
                return False
        
        return True

优势

  • 结合了双向扫描的优点
  • 处理边缘情况的能力强
  • 代码简洁高效

方法比较

解法时间复杂度空间复杂度优势劣势
双向扫描法O(n)O(1)简单直观,易于理解需要两次扫描
贪心算法O(n)O(n)可以知道具体修改方案空间消耗较大
平衡范围计算法O(n)O(1)单次扫描,概念清晰理解难度较高
改进的计数分析法O(n)O(1)结合多种优点,健壮性强需要两次扫描

实例分析

以下是一个具体的测试案例:

s = "))(()(()(()))(()((()))((()))))(((((((())))))("
locked = "10001111011001101101011110011101110111111000010100110100111"

这个例子中,字符串以锁定的右括号开始,使用以上解法可以迅速判断出它不可能变为有效序列。

总结与思考

这四种解法展示了解决括号匹配问题的不同思路,从简单的双向扫描到更复杂的平衡范围计算。每种方法都有其独特的优势和适用场景。在实际应用中,可以根据具体需求选择合适的算法。

关键的解题思想包括:

  1. 利用括号匹配的特性
  2. 巧妙使用计数和平衡概念
  3. 考虑问题的不同约束条件
  4. 通过多角度思考提高算法效率

这个问题不仅是算法能力的考验,也是思维灵活性的展示。

相关文章:

  • C语言指针
  • 云原生 | 下一代CI/CD工具,Tekton入门部署指南
  • C++学习:六个月从基础到就业——C++基础语法回顾:控制流语句
  • Spark2 之 Expression/Functions
  • Simple-BEV的bilinear_sample 作为view_transformer的解析,核心是3D-2D关联点生成
  • 穿越之程序员周树人的狂人日记Part3__人机共生纪元
  • Extend module 01:Keyboard
  • 具身系列——NLP工程师切入机器人和具身智能方向
  • LabVIEW液压振动锤控制系统
  • 清华大学.智灵动力-《DeepSeek行业应用实践报告》附PPT下载方法
  • 查询操作是否需要使用事务?
  • 软件测试面试:支付功能如何测试?
  • 基于Python的机器学习入门指南
  • 【Pandas】pandas Series plot.line
  • TCP netstat TIME_WAIT CLOSE_WAIT
  • 利用dify打造命令行助手
  • 基于SpringBoot + Vue 的垃圾分类管理系统
  • Qt信号与槽机制入门详解:从基础语法到界面交互实战
  • 测试用例组成及设计方法
  • Zotero·Awesome GPT配置
  • 解放日报:“北斗七星”列阵,AI群星闪耀
  • 司法服务保障西部陆海新通道建设,最高法专门发文
  • 坚持科技创新引领,赢得未来发展新优势
  • 交通运输部:预计今年五一假期全社会跨区域人员流动量将再创新高
  • 初步结果显示加拿大自由党赢得大选,外交部回应
  • 北京动物园:大熊猫“萌兰”没有参加日本大阪世博会的计划