一 题目描述
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()" 输出:true
示例 2:
输入:s = "()[]{}" 输出:true
示例 3:
输入:s = "(]" 输出:false
二 方法代码
思路讲解:
括号都是成对出现的,并且它的特性是,如果两对括号是包含关系,那么一定是嵌套的,类似于洋葱,即内层括号对应一组,外层对应一组,例如“( [ { } ] )”或者( [ ] { }),不会乱套,不会出现内层括号是” { ] “这样不对应的组合。
因此,当我们取出一个右括号时,要去看它前一个的左括号是不是对应的,如果是,就消掉,如果不是就错误;如果是左括号,我们就存储起来,等着遇到下一个右括号。这个就对应哈希表Key-Value的映射关系,因此我们需要使用哈希表
依照这个思路,我们可以联想到堆栈,只能从一端进行元素的添加和删除的操作受限的线性表为栈,它具有后进先出(LIFO,Last In First Out)的特性。因此我先遇到的左括号压在栈底,后遇到的左括号放在栈顶,当遇到右括号,需要取出上一个最近的左括号时,拿出栈顶就好。
不过现在Java都使用Deque(双端队列)来替代堆栈,因为Deque既可以当队列也可以当堆栈,这是Deque的一些使用方法的等效对应方法,来源自Java数据结构之Deque(双端队列)_java deque-CSDN博客
-
方法一
public boolean isValid1(String s) {
if(s.length() % 2 == 1){
//因为括号成对出现,所以长度一定是偶数
return false;
}
Map<Character, Character> map = new HashMap<Character, Character>(){
{
//哈希表,注意key是右括号,因为要遇到右括号后要去双向队列中消除左括号
put(')', '(');
put(']', '[');
put('}', '{');
}
};
//创建双向队列,即又可以当堆栈也可以当队列,可以在两端进行插入和删除
Deque<Character> stack = new LinkedList<Character>();
for(int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if(map.containsKey(c)){//当取到的是右边括号的时候
//如果队列为空,所以没有对应的左括号,一定是错的
//如果从前端取出的元素不是相对应的左括号,也一定是错的
if(stack.isEmpty() || stack.peekFirst() != map.get(c)){
return false;
}
//如果没有返回false,说明队列中找到了对应的左括号,就删除掉前端的第一个元素
//pop()等效于Deque的removeFirst()方法
stack.pop();
}else{//当取到的是左括号时,就插入到前端中
//因为括号都是对应出现的,取到的第一个右括号应该对应最后出现的左括号
//eg: ([]),第一个取到的右括号 ']' 对应最后出现的左括号 '['
//因此,左括号要插入到前端而不是后端,这样peekFirst拿到的就是后出现的左括号
stack.addFirst(c);
}
}
//如果最后队列为空,说明都可以两两对应抵消掉
return stack.isEmpty();
}
-
方法二
这个是我在力扣评论区找到的,运行速度要快:本链接导向大佬的力扣评论区
因为HashMap创建的键值对需要时间,所以会耽误运行速度。其本质就是一个对应关系,因此大佬直接修改思路,让当取出左括号时,就直接插入对应的右括号到栈中,这样就省去了HashMap的运行时间
为什么不像上一个方法一样key为右括号,然后遇到右括号压左括号入栈,而是取出左括号后将右括号压入栈中,是因为思路相反,上一个是遇到右括号后取出栈顶的左括号看是否对应,这个思路是遇到左括号后,直接将对应的右括号压入栈,这样当遇到第一个右括号时,就取出栈顶的理论上正确的右括号取出,做对比看是否一致,一致说明没问题,看下一个括号,不一致就返回错误
缺点是不易于维护和修改,把字符配对处理放一起的话,后续扩展会比较好,比如再加<>配对,大佬的这个修改会有些麻烦,也容易出错,代码设计其中一个原则:对扩展开放,对修改关闭。
public boolean isValid2(String s) {
if(s.length() % 2 == 1){
//因为括号成对出现,所以长度一定是偶数
return false;
}
Stack<Character>stack = new Stack<Character>();
//把字符串转为字符数组,然后逐个遍历,
for(char c: s.toCharArray()){
if(c=='('){
//将左括号对应的右括号压入栈,下面else if的同理
stack.push(')');
}
else if(c=='['){
stack.push(']');
}
else if(c=='{'){
stack.push('}');
}
//剩下的情况是取出右括号了,那就拿出栈顶的正确的右括号做对比看是否一致
else if(stack.isEmpty()||c!=stack.pop()){
return false;
}
}
return stack.isEmpty();
}
三 运行结果
方法一:
方法二: