Go---用栈解决括号匹配问题

473 阅读3分钟

栈(stack)是一种先进后出(FILO)的数据结构,在遇到某些问题时,使用栈也许能更有效地解决这些问题。

括号匹配问题

给定一个只包括 (){}[] 的字符串,判断字符串是否合法。
有效字符串需满足:
1、左括号必须用相同类型的右括号闭合。
2、左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

解决问题

分析

  • 通常情况下,我们会想到将所有字符逐个遍历,然后通过很多条件,最终得出字符串是否合法,但这种方法比较繁琐,会有比较多的判断条件。
  • 由于这个问题是不允许括号嵌套,即类似 ({)} 这种形式,所以可以肯定,每一个合法的字符串中的每一个左括号始终是能与对应的右括号相匹配,而不用担心顺序问题,在这种情况下,我们可以考虑通过栈这种数据结构来解决这个问题。
  • 每当遇到左括号时,就将这个括号压入栈中,当遇到右括号的时候,将栈顶元素弹出,这个栈顶元素就是距离右括号最近的左括号。判断二者是否匹配。如果所有字符都能像这样匹配,则说明该字符串合法,反之,只要有一个括号没有与之相匹配的括号,则认为该字符串不合法。

go代码实现

package main

import "fmt"

// 括号匹配
func main() {
   // 定义一个栈
   stack := make([]rune, 0)
   // 定义一个括号字符串
   str := "()({})[saf]{faa}"
   // 定义一个括号map
   bracket := map[rune]rune{
      '(': ')',
      '{': '}',
      '[': ']',
   }
   // 将str中的每个字符逐个取出,如果是左括号,则压栈,
   // 如果是右括号,则将栈顶元素弹出,如果栈顶元素与右括号匹配,
   // 则继续判断,直到字符全部判断完毕;如果栈顶元素与右括号不匹配,
   // 则括号匹配失败,该字符串不是一个合法的字符串
   for _, c := range str {
      switch c {
      case '(', '{', '[':
         {
            // 将c压栈
            stack = append(stack, c)
            break
         }
      case ')', '}', ']':
         {
            // 将stack中的栈顶元素弹出并与c匹配
            // 匹配成功则继续,失败则结束
            if len(stack) == 0 {
               // 栈为空,不可能有与该右括号匹配的左括号,不是一个合法的字符串
               fmt.Printf("%s  不是一个合法的字符串\n", str)
               return
            }
            temp := stack[len(stack)-1]
            stack = stack[:len(stack)-1]
            if bracket[temp] == c {
               break
            }
            fmt.Printf("%s  不是一个合法的字符串\n", str)
            return
         }
      default:
         break
      }
   }
   // 如果最后栈不为空,则字符串不合法
   if len(stack) != 0 {
      fmt.Printf("%s  不是一个合法的字符串\n", str)
      return
   }
   // for循环顺利结束,所有括号均能匹配成功,str是一个合法的字符串
   fmt.Printf("%s  是一个合法的字符串\n", str)
   return
}

结语

从括号匹配问题中可以发现,栈可以很好地应对这种匹配/消除类问题,如果再遇到这种类似的问题,可以优先考虑使用栈来解决。