题目
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
示例 4:
输入:s = "([])"
输出:true
分析
括号匹配问题的核心是“后进先出”的原则,这正是栈数据结构的特点。栈是一种线性数据结构,遵循后进先出的原则(LIFO,Last In First Out),非常适合用于处理这种嵌套结构的问题。
当遇到左括号时,将其压入栈中;当遇到右括号时,检查栈顶元素是否为相应的左括号。如果匹配,则将栈顶元素弹出;如果不匹配或者栈为空,则说明括号不平衡。
逻辑流程:
- 初始化栈:首先声明一个空的
stack
切片,用于保存遇到的左括号。 - 遍历字符串:通过
for
循环遍历字符串中的每个字符,逐一进行处理。- 如果遇到左括号
(
、[
、{
,将其压入栈中。 - 如果遇到右括号
)
、]
、}
,则:- 检查栈是否为空。如果栈为空,说明当前右括号没有对应的左括号,直接返回
false
。 - 如果栈不为空,取出栈顶元素,检查这个栈顶元素是否与当前右括号匹配(即是否是相对应的左括号)。括号的匹配是通过比较它们的 ASCII 值来实现的。例如,
)
与(
的 ASCII 值相差 1,而]
与[
以及}
与{
的 ASCII 值相差 2。 - 如果匹配成功,弹出栈顶元素;如果不匹配,返回
false
。
- 检查栈是否为空。如果栈为空,说明当前右括号没有对应的左括号,直接返回
- 如果遇到左括号
- 最终检查栈:遍历完字符串后,如果栈为空,说明所有的括号都已经成功匹配,返回
true
;否则,返回false
。
详见代码
// isValid 函数用于判断一个包含括号的字符串是否有效。
// 有效的定义是:每个左括号必须有对应的右括号,括号之间必须正确闭合。
func isValid(s string) bool {
// 如果字符串长度为 0,直接返回 true,因为空字符串被认为是有效的。
if len(s) == 0 {
return true
}
//如果字符串长度为奇数,那么说明一定无法闭合括号,返回false
if len(s)%2 != 0{
return false
}
// 初始化一个栈,用于存储左括号
var stack []rune
// 遍历字符串中的每一个字符
for _, v := range s {
// 如果是左括号('(', '[', '{'),将其压入栈中
if v == '(' || v == '[' || v == '{' {
stack = append(stack, v)
} else if v == ')' || v == ']' || v == '}' { // 如果是右括号
// 如果栈为空,意味着没有匹配的左括号,返回 false
if len(stack) == 0 {
return false
}
// 获取栈顶元素(最后一个压入的左括号)
top := stack[len(stack)-1]
// 检查右括号是否与栈顶的左括号匹配
// ')' 对应 '(' 的 ASCII 值相差 1
// ']' 对应 '[' 的 ASCII 值相差 2
// '}' 对应 '{' 的 ASCII 值相差 2
if v == top+1 || v == top+2 {
// 如果匹配,弹出栈顶元素
stack = stack[:len(stack)-1]
} else {
// 如果不匹配,返回 false
return false
}
}
}
// 如果栈为空,说明所有的左括号都被正确匹配,返回 true
// 如果栈不为空,说明还有未匹配的左括号,返回 false
return len(stack) == 0
}