括号补全问题|豆包MarsCode AI刷题

154 阅读6分钟

解题思路

括号补全问题是典型的字符串处理问题,主要目标是判断一个给定的括号字符串是否有效,并计算最少需要插入多少个括号才能使其有效。括号字符串的有效性有以下几种情况:

  1. 它是一个空字符串。
  2. 它可以写成两个有效字符串的连接形式,即 AB。
  3. 它可以写成 (A) 的形式,其中 A 是有效字符串。

为了使括号字符串有效,我们需要确保每一个右括号 ) 都有一个匹配的左括号 (,并且左括号的数量与右括号的数量相等。如果右括号没有匹配的左括号,我们需要插入一个左括号;如果左括号有多余的没有匹配的右括号,我们需要插入相应的右括号。

算法设计

  1. 使用栈进行匹配:栈是一种非常适合解决括号匹配问题的数据结构。我们可以使用栈来存储未匹配的左括号。
  2. 遍历字符串:从左到右遍历字符串中的每个字符。
  3. 字符处理
    • 如果遇到左括号 (,将其压入栈中。
    • 如果遇到右括号 ),检查栈是否为空:
      • 如果栈为空,说明没有匹配的左括号,需要插入一个左括号。
      • 如果栈不为空,弹出栈顶的左括号,表示匹配成功。
  4. 栈剩余处理:遍历结束后,栈中剩余的左括号需要插入相应数量的右括号才能使字符串有效。
  5. 返回结果:最终返回插入的括号数量。

代码分析

代码主要部分如下:

def solution(s: str) -> int:
    stack = []
    insert_count = 0
    for char in s:
        if char == '(':
            stack.append(char)
        elif char == ')':
            if not stack:
                insert_count += 1
            else:
                stack.pop()
    insert_count += len(stack)
    return insert_count
  • 初始化栈和插入计数stack = [] 用于存储未匹配的左括号,insert_count = 0 用于记录需要插入的括号数量。
  • 遍历字符串for char in s 遍历字符串中的每个字符。
  • 左括号处理if char == '(',将左括号压入栈中。
  • 右括号处理elif char == ')',检查栈是否为空:
    • if not stack,栈为空时,说明需要插入一个左括号,insert_count += 1
    • else,栈不为空时,弹出栈顶的左括号,表示匹配成功,stack.pop()
  • 栈剩余处理:遍历结束后,栈中剩余的左括号需要插入相应数量的右括号,insert_count += len(stack)
  • 返回结果:最终返回 insert_count

可能出现的问题

  1. 栈溢出:如果输入的字符串非常长,栈可能会溢出。Python 的列表作为栈使用时,一般不会出现栈溢出的问题,但如果在其他语言中使用栈,需要注意栈的大小限制。

  2. 字符类型检查:输入字符串中可能包含非括号字符。虽然题目假设输入只包含 (),但在实际应用中仍需进行检查。

    if char not in {'(', ')'}:
        raise ValueError("字符串中包含非法字符")
    
  3. 性能问题:对于较长的字符串,遍历和栈操作可能会导致性能下降。虽然当前算法的时间复杂度为 O(n),但在某些极端情况下(例如字符串全是左括号或右括号),性能可能会受到影响。

个人的思考与改进

  1. 字符类型检查

    • 在遍历字符串之前,检查字符串中是否包含非法字符,可以提高代码的健壮性。
    if any(c not in {'(', ')'} for c in s):
        raise ValueError("字符串中包含非法字符")
    
  2. 减少栈的使用

    • 使用计数器来替代栈,减少对栈的依赖。可以使用两个计数器,一个记录未匹配的左括号数量,一个记录未匹配的右括号数量。
    def solution(s: str) -> int:
        left_count = 0
        insert_count = 0
        for char in s:
            if char == '(':
                left_count += 1
            elif char == ')':
                if left_count == 0:
                    insert_count += 1
                else:
                    left_count -= 1
        insert_count += left_count
        return insert_count
    
  3. 优化遍历

    • 通过一次遍历,同时处理未匹配的左括号和右括号,可以简化代码逻辑。
    def solution(s: str) -> int:
        left_count = 0
        insert_count = 0
        for char in s:
            if char == '(':
                left_count += 1
            elif char == ')':
                if left_count > 0:
                    left_count -= 1
                else:
                    insert_count += 1
        insert_count += left_count
        return insert_count
    
  4. 代码结构优化

    • 将字符类型检查和括号匹配逻辑封装成单独的函数,提高代码的可读性和可维护性。
    def is_valid_char(c: str) -> bool:
        return c in {'(', ')'}
    
    def solution(s: str) -> int:
        if not all(is_valid_char(c) for c in s):
            raise ValueError("字符串中包含非法字符")
        left_count = 0
        insert_count = 0
        for char in s:
            if char == '(':
                left_count += 1
            elif char == ')':
                if left_count > 0:
                    left_count -= 1
                else:
                    insert_count += 1
        insert_count += left_count
        return insert_count
    
  5. 进一步优化

    • 如果字符串中包含其他括号(例如 []{}),可以扩展算法来处理这些括号。
    • 使用字典来存储括号的匹配关系,可以方便地扩展到多种括号类型。
    def solution(s: str) -> int:
        if not all(c in {'(', ')', '[', ']', '{', '}'} for c in s):
            raise ValueError("字符串中包含非法字符")
        stack = []
        insert_count = 0
        bracket_map = {')': '(', ']': '[', '}': '{'}
        for char in s:
            if char in bracket_map.values():
                stack.append(char)
            elif char in bracket_map.keys():
                if not stack or stack.pop() != bracket_map[char]:
                    insert_count += 1
        insert_count += len(stack)
        return insert_count
    
  6. 多线程优化

    • 对于非常长的字符串,可以考虑使用多线程或并行计算来加速处理。例如,可以将字符串分成多个子字符串,分别计算每个子字符串的插入次数,最后汇总结果。
  7. 数学优化

    • 从数学角度考虑,可以推导出一个更高效的公式来计算插入的括号数量。例如,可以通过两次遍历来分别计算未匹配的左括号和右括号数量,然后再进行汇总。
    def solution(s: str) -> int:
        left_count = 0
        right_count = 0
        for char in s:
            if char == '(':
                left_count += 1
            elif char == ')':
                if left_count > 0:
                    left_count -= 1
                else:
                    right_count += 1
        return left_count + right_count
    

结论

通过上述分析和改进,我们可以看到,括号补全问题可以通过栈或计数器来高效解决。栈方法在处理括号匹配时直观且易于理解,而计数器方法则更加简洁且性能更高。通过增加字符类型检查和优化遍历逻辑,可以提高代码的健壮性和可读性。进一步的优化,如多线程和数学公式优化,可以在特定情况下提供更好的性能。希望这篇读书笔记对理解和优化括号补全问题有所帮助。