返回

披荆斩棘,探寻算法的奥妙:括号的有效性

前端

踏上算法之旅,我们将深入探索有效括号的奥秘。在括号的世界里,我们必须确保左括号与对应的右括号正确匹配,并且括号的闭合顺序必须合理。通过精心设计的栈数据结构,我们将解开有效括号的谜题,挖掘算法的无穷魅力。

有效括号的内涵

有效括号的定义看似简单,却蕴藏着算法的智慧。有效括号需要满足以下两个条件:

  1. 匹配成对: 左括号必须与相同类型的右括号匹配,例如圆括号()、方括号[]和大括号{}。
  2. 闭合顺序正确: 左括号必须以正确的顺序闭合,即先开的括号必须先闭合。

例如,以下括号序列都是有效的:

  • "()"
  • "{}"
  • "[]"
  • "{[]}"
  • "([{}])"

以下括号序列都是无效的:

  • "([)]"
  • "}{"
  • "([]"
  • "){"

栈:算法的利器

栈是一种先进后出(LIFO)的数据结构,它就像一个弹簧,先放进的元素会后出来。栈在算法中扮演着重要的角色,它可以帮助我们解决各种问题,包括有效括号问题。

为了判断一个括号序列是否有效,我们可以使用栈来模拟括号的闭合过程。当我们遇到一个左括号时,我们将它压入栈中。当我们遇到一个右括号时,我们将它与栈顶的左括号进行比较。如果两者匹配,我们将它们弹出栈外。如果两者不匹配,那么括号序列就是无效的。

例如,对于括号序列 "()[]{}", 我们可以使用栈来模拟它的闭合过程:

  1. 遇到左括号 "(", 将它压入栈中。
  2. 遇到右括号 ")", 将它与栈顶的左括号比较,两者匹配,将它们弹出栈外。
  3. 遇到左方括号 "[", 将它压入栈中。
  4. 遇到右方括号 "]", 将它与栈顶的左方括号比较,两者匹配,将它们弹出栈外。
  5. 遇到左大括号 "{", 将它压入栈中。
  6. 遇到右大括号 "}", 将它与栈顶的左大括号比较,两者匹配,将它们弹出栈外。

经过上述模拟过程,栈中已经没有元素了,这说明括号序列 "()[]{}" 是有效的。

算法实现

现在,让我们将栈的思想应用到算法实现中。我们可以使用Python来实现一个判断括号序列是否有效的函数:

def is_valid(s):
    stack = []
    for char in s:
        if char in "([{":
            stack.append(char)
        elif char in ")]}":
            if not stack:
                return False
            top = stack.pop()
            if (top == "(" and char != ")") or (top == "[" and char != "]") or (top == "{" and char != "}"):
                return False
    return not stack

这个函数首先创建一个空栈。然后,它遍历字符串 s 中的每个字符。如果字符是左括号,则将其压入栈中。如果字符是右括号,则将其与栈顶的左括号进行比较。如果两者匹配,则将它们弹出栈外。如果两者不匹配,则返回 False。最后,如果栈中没有元素,则返回 True,否则返回 False。

算法的复杂度

判断括号序列是否有效的算法的复杂度为 O(n),其中 n 是字符串 s 的长度。这是因为算法只需要遍历字符串 s 中的每个字符一次。

结语

有效括号问题是一个经典的算法问题,它不仅考验算法设计者的思维能力,也考验他们的编程能力。通过栈数据结构,我们可以轻松解决有效括号问题,并从中领略到算法的魅力。