20. 有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

**输入:**s = “()”

**输出:**true

示例 2:

**输入:**s = “()[]{}”

**输出:**true

示例 3:

**输入:**s = “(]”

**输出:**false

示例 4:

**输入:**s = “([])”

**输出:**true

示例 5:

**输入:**s = “([)]”

**输出:**false

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

使用数据结构中的栈后进先出(LIFO)逻辑,如果第一个括号出现,则末端必然有匹配的括号,如果不匹配则错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>
#include <string.h>
#include <stdbool.h> // C99 标准,为了使用 bool true false

bool isValid(char *s) {
// 1. 获取字符串长度
int len = strlen(s);

// 如果长度是奇数,肯定没法两两配对,直接错
if (len % 2 != 0) return false;

// 2. 准备“盒子”
// 题目说最长 10000,我们开个够大的数组
char box[10001];

// top 代表“手指”的位置。
// 初始状态盒子是空的,手指指向 -1 (数组下标从0开始,-1表示没东西)
int top = -1;

// 3. 遍历字符串的每一个字符
for (int i = 0; i < len; i++) {
char current = s[i]; // 当前拿到的字符

// --- 情况 A: 遇到左括号 ---
// 只要是左边的,不管三七二十一,先放进盒子里
if (current == '(' || current == '[' || current == '{') {
top++; // 手指往上移一格
box[top] = current; // 把字符存进去
}
// --- 情况 B: 遇到右括号 ---
else {
// 首先检查:盒子里有东西吗?
// 如果来了右括号,盒子却是空的(top == -1),说明前面没有左括号能跟它配,错!
if (top == -1) {
return false;
}

// 取出盒子最上面的那个字符来看看
char peak = box[top];

// 检查是否匹配:
// 如果是 ')',那盒子顶端必须是 '(',否则就错
if (current == ')' && peak != '(') return false;
if (current == ']' && peak != '[') return false;
if (current == '}' && peak != '{') return false;

// 如果代码走到这里,说明匹配成功了!
// 既然抵消了,手指就往下移一格(相当于把那个左括号扔了)
top--;
}
}

// 4. 循环结束后的最终审判
// 如果 top 回到了 -1,说明盒子里空了,所有括号都完美抵消,返回 true
// 如果 top > -1,说明盒子里还有剩余的左括号(比如 "(()" 这种情况),返回 false
return top == -1;
}