难度:简单
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
1、左括号必须用相同类型的右括号闭合。
2、左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
这个题一看到题第一想法就建栈,左括号压栈进去,然后若有右括号与之匹配,则一起出栈,到最后直接判定栈是否为空,空的话说明全部匹配上则true,非空说明有没匹配上的false。
图解——栈
以()[]{}
为例,返回true
后面的[]{}
同理,最后栈为空,说明全都匹配上了,再来看一个不匹配的例子
以 ([)]
为例
注解知识:
stack.peek() 与 stack.pop() 的区别
-
相同点:大家都返回栈顶的值。
-
不同点:peek 不改变栈的值(不删除栈顶的值),pop会把栈顶的值删除。
代码:
class Solution {
public boolean isValid(String s) {
int len = s.length();
//空字符串可被认为是有效字符串
if(s.length() == 0)
return true;
/*新建一个栈,左括号压栈进去,然后若有右括号与之匹配,则出栈,
若最后栈完全空了,则说明都匹配上了*/
Stack<Character> stack = new Stack<Character>();
for(int i=0;i<len;i++){
switch(s.charAt(i)){
case '(':
stack.push(s.charAt(i));
break;
case '[':
stack.push(s.charAt(i));
break;
case '{':
stack.push(s.charAt(i));
break;
case ')':
if(!stack.empty() && stack.peek()=='(')
stack.pop();
else
//如果栈内没有与之匹配的左括号,那右括号也不必进栈了
//直接返回false即可
return false;
break;
case ']':
if(!stack.empty() && stack.peek()=='[')
stack.pop();
else
return false;
break;
case '}':
if(!stack.empty() && stack.peek()=='{')
stack.pop();
else
return false;
break;
default:
throw new IllegalArgumentException("Illegal character");
}
}
if(stack.empty())
return true;
return false;
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),只需遍历一遍括号字符串
- 空间复杂度:
O
(
n
)
O(n)
O(n),当我们将所有的开括号都推到栈上时以及在最糟糕的情况下,我们最终要把所有括号推到栈上。例如
((((((((((
。
本题还有很多其他的实现,不管是建立哈希表还是switch…case…,但是主要思想都是栈。
下面是官方用Python语言做出的题解。
虽然仍是建栈,但是使用了字典,将左右匹配的括号化身为键值对,这样可以轻松的将左右括号得以区分,再判断的时候也非常方便。
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
# 建栈
stack = []
# 建立字典
# 这个字典的妙处就在于将左右括号通过键值对的形式区分开了!
mapping = {")": "(", "}": "{", "]": "["}
for char in s:
# 如果字符是右括号(char此时是键,键为右括号)
if char in mapping:
# 如果栈不为空,则从栈中弹出最上面的元素
# 否则,将顶层元素赋值为"#"
top_element = stack.pop() if stack else '#'
# 如果哈希表中的左括号( mapping[char]为值,值为左括号)与堆栈的顶部元素的映射不匹配,返回False
if mapping[char] != top_element:
return False
else:
# 如果左括号,直接进栈
stack.append(char)
# 如果栈最后为空,则我们匹配成功,是有效的括号
return not stack