一、题目
1.1 题目说明
给定一个只包括 ‘(',')','{','}','[',']’ 的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
示例 2:
| 1
2
 | 输入: "()[]{}"
输出: true
 | 
示例 3:
示例 4:
示例 5:
leetcode地址
1.2 题目知识点介绍
这道题目主要是考核堆栈这个数据结构,它是一个先进先出、操作受限的线性表,也称为 栈。

- 栈的两种基本的操作 - 入栈 push: 往栈中最顶端插入数据
- 出栈 pop: 从栈中删除最顶端的数据
 
- 栈的实现方式 
手动实现一个栈
二、题解
2.1 栈实现
代码:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
 | func isValid(s string) bool {
	var stack []byte
	pairs := map[byte]byte{
		')': '(',
		']': '[',
		'}': '{',
	}
	for i := range s {
		if pairs[s[i]] > 0 { // 这里如果没匹配到,是 byte 默认值 0
			if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] { // 栈顶 Top() 匹配期望值
				return false
			}
			stack = stack[:len(stack)-1] // 移除栈顶 Pop()
		} else {
			stack = append(stack, s[i])
		}
	}
	return len(stack) == 0
}
 | 
小优化:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 | func isValid(s string) bool {
	if len(s)&1 == 1 {
		return false
	}
	var stack []byte
	pairs := map[byte]byte{
		')': '(',
		']': '[',
		'}': '{',
	}
	for i := range s {
		if pairs[s[i]] > 0 { // 这里如果没匹配到,是 byte 默认值 0
			if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] { // 栈顶 Top() 匹配期望值
				return false
			}
			stack = stack[:len(stack)-1] // 移除栈顶 Pop()
		} else {
			stack = append(stack, s[i])
		}
	}
	return len(stack) == 0
}
 | 
成绩:
执行用时:0 ms, 在所有 Go 提交中击败了100.00%的用户
内存消耗:2 MB, 在所有 Go 提交中击败了91.93%的用户
栈的操作图:

2.2 非栈实现
代码:
| 1
2
3
4
5
6
7
8
 | func isValid(s string) bool {
   var l int
   for ok := true; ok; ok = l != len(s) {
      l = len(s)
      s = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(s, "()", ""), "{}", ""), "[]", "")
   }
   return len(s) == 0
}
 | 
- 平均时间复杂度是 $ O^2/2 $,字符串替换是 n,for 循环是 n,所以是 n 平方
- 虽然代码很精简,但是时间和空间复杂度的表现都不是很好
成绩:
执行用时:8 ms, 在所有 Go 提交中击败了7.18%的用户
内存消耗:7.1 MB, 在所有 Go 提交中击败了5.07%的用户
2.3 小结
- 强烈建议使用栈来实现
- 栈的逻辑是:如果是左边括号就入栈,如果遇到右边括号就去查询栈顶元素,如果是与之匹配的左边括号的话就取出元素,否则就不匹配返回,执行到最后查看栈是否为空,空的话就是匹配的
- 记得对边界条件做处理,比如字符串长度是奇数的处理
- 空字符串也是满足的
本章的代码连接