算法思路
本题堪称经典,使用了Map,List两个集合类,同时引入栈来处理,使问题简单化。
- 首先定义HashMap用于存放一对括号的键值对;
- 如果首字母不是左括号,直接返回false;
- 在声明一个LinkedList,用于对输入的字符串处理,由于会频繁的向集合中插入,删除集合,所以使用LinkedList而不是用ArrayList,ArrayList在查询时效率更高,这里还可以用Stack类用于声明;
- 先向LinkedList集合中添加一个元素“?”,用于边界处理,否则集合LinkedList在removeLast()时会报错;
- 依次遍历输入的字符串,判断当前字符是不是左括号,若是就添加在LinkedList集合中,不是就将将LinkedList集合中最后一个元素删除,并判断删除的元素(作为键)在map中的值是不是对应的,不是就直接返回false,是就继续下一个字符;
- 最后判断LinkedList集合的size是否为1,如果集合括号都是有效的,LinkedList集合的元素就只有“?”,size为1,返回true;否则size不为1,返回false。
代码
class Solution {
public boolean isValid(String s) {
HashMap<Character,Character> hmap = new HashMap<Character,Character>(); //不能够用char
hmap.put('{','}');
hmap.put('[',']');
hmap.put('(',')');
if(s.length() > 0 && !hmap.containsKey(s.charAt(0))) //判断首字符是否存在hmap的键中
return false;
LinkedList<Character> stack = new LinkedList<Character>() ; //使用LinkedList而不是用ArrayList是因为 LinkedList便于向集合中插入或者删除元素
stack.add('?'); //先ADD一个字符,否则在处理"[])"时会报错
for(Character c : s.toCharArray()){
if(hmap.containsKey(c)) stack.addLast(c);//如果c在hmap的键中存在,就将c入栈,否则就删除栈中最后一个字符,
//并判断该删除的键对应的值和当前字符是否相等,若不相等则返回false,相等就继续执行下一个字符
else if(hmap.get(stack.removeLast()) != c) return false;
}
return stack.size() == 1;//若都是有效括号,到最后栈stack中只存在‘?’,size为1
}
}
复杂度
时间复杂度:O(n)O(n),因为我们一次只遍历给定的字符串中的一个字符并在栈上进行 O(1)O(1) 的推入和弹出操作。
空间复杂度:O(n)O(n),当我们将所有的开括号都推到栈上时以及在最糟糕的情况下,我们最终要把所有括号推到栈上。例如 ((((((((((。
总结list map stack
ArrayList 类和 LinkedList 类的区别
ArrayList 与 LinkedList 都是 List 接口的实现类,因此都实现了 List 的所有未实现的方法,只是实现的方式有所不同。
ArrayList 是基于动态数组数据结构的实现,访问元素速度优于 LinkedList。LinkedList 是基于链表数据结构的实现,占用的内存空间比较大,但在批量插入或删除数据时优于 ArrayList。
对于快速访问对象的需求,使用 ArrayList 实现执行效率上会比较好。需要频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高。
不同的结构对应于不同的算法,有的考虑节省占用空间,有的考虑提高运行效率,对于程序员而言,它们就像是“熊掌”和“鱼肉”,不可兼得。高运行速度往往是以牺牲空间为代价的,而节省占用空间往往是以牺牲运行速度为代价的。
参考
https://leetcode-cn.com/problems/valid-parentheses/solution/you-xiao-de-gua-hao-by-leetcode/
http://c.biancheng.net/view/6868.html