 >优质博文:IT-BLOG-CN
>优质博文:IT-BLOG-CN
一、题目
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串s,判断字符串是否有效。
有效字符串需满足:
 【1】左括号必须用相同类型的右括号闭合。
 【2】左括号必须以正确的顺序闭合。
 【3】每个右括号都有一个对应的相同类型的左括号。
示例 1:
 输入:s = “()”
 输出:true
示例 2:
 输入:s = “()[]{}”
 输出:true
示例 3:
 输入:s = “(]”
 输出:false
1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成
二、代码
判断括号的有效性可以使用「栈」这一数据结构来解决。
我们遍历给定的字符串s。当我们遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶。
当我们遇到一个右括号时,我们需要将一个相同类型的左括号闭合。此时,我们可以取出栈顶的左括号并判断它们是否是相同类型的括号。如果不是相同的类型,或者栈中并没有左括号,那么字符串s无效,返回False。为了快速判断括号的类型,我们可以使用哈希表存储每一种括号。哈希表的键为右括号,值为相同类型的左括号。
在遍历结束后,如果栈中没有左括号,说明我们将字符串s中的所有左括号闭合,返回True,否则返回False。
注意到有效字符串的长度一定为偶数,因此如果字符串的长度为奇数,我们可以直接返回False,省去后续的遍历判断过程。
class Solution {public boolean isValid(String s) {// 判断是否为偶数,不是直接推出if (s == null || s.trim().length() <= 0 || (s.trim().length() & 1) == 1 ) {return false;}// 将 '(',')','{','}','[',']' 存放之 map中Map<Character, Character> pairs = new HashMap<Character, Character>();pairs.put(')','(');pairs.put('}','{');pairs.put(']','[');// 维护一个栈Deque<Character> stack = new LinkedList<Character>();for (int i = 0; i < s.length(); i++) {// 如果拿到了一个闭环的括号,则比较栈和集合中的元素是否相同if (pairs.containsKey(s.charAt(i))) {// peek 方法时查看头部元素,不影响栈的结构,不能使用pop,会影响栈的结构if (stack.isEmpty() || stack.peek() != pairs.get(s.charAt(i))) {return false;}// 如果相同,则将栈中元素弹出stack.pop();} else {// 如果不是闭环,则压栈stack.push(s.charAt(i));}}return stack.isEmpty();}
}
时间复杂度: O(n),其中n是字符串s的长度。
 空间复杂度: O(n+∣Σ∣),其中Σ表示字符集,本题中字符串只包含6种括号,∣Σ∣=6。栈中的字符数量为O(n),而哈希表使用的空间为O(∣Σ∣),相加即可得到总空间复杂度。
C++精简版
class Solution {
public:bool isValid(string s) {stack<int> st;for (int i = 0; i < s.size(); i++) {if (s[i] == '(' || s[i] == '[' || s[i] == '{') st.push(i);else {if (st.empty()) return false;if (s[i] == ')' && s[st.top()] != '(') return false;if (s[i] == '}' && s[st.top()] != '{') return false;if (s[i] == ']' && s[st.top()] != '[') return false;st.pop();}}return st.empty();}
};
高级版解题思路: 栈先入后出特点恰好与本题括号排序特点一致,即若遇到左括号入栈,遇到右括号时将对应栈顶左括号出栈,则遍历完所有括号后stack仍然为空;建立哈希表dic构建左右括号对应关系:key左括号,value右括号;这样查询2个括号是否对应只需O(1)时间复杂度;建立栈stack,遍历字符串s并按照算法流程一一判断。
算法流程: 如果c是左括号,则入栈push;否则通过哈希表判断括号对应关系,若stack栈顶出栈括号stack.pop()与当前遍历括号c不对应,则提前返回false。
**提前返回优点:**在迭代过程中,提前发现不符合的括号并且返回,提升算法效率。
解决边界问题: 栈stack为空: 此时stack.pop()操作会报错;因此,我们采用一个取巧方法,给stack赋初值?,并在哈希表dic中建立key:′?′,value:′?′的对应关系予以配合。此时当stack为空且c为右括号时,可以正常提前返回false
字符串s以左括号结尾: 此情况下可以正常遍历完整个s,但stack中遗留未出栈的左括号;因此,最后需返回len(stack) == 1,以判断是否是有效的括号组合。
class Solution {private static final Map<Character,Character> map = new HashMap<Character,Character>(){{put('{','}'); put('[',']'); put('(',')'); put('?','?');}};public boolean isValid(String s) {if(s.length() > 0 && !map.containsKey(s.charAt(0))) return false;LinkedList<Character> stack = new LinkedList<Character>() {{ add('?'); }};for(Character c : s.toCharArray()){if(map.containsKey(c)) stack.addLast(c);else if(map.get(stack.removeLast()) != c) return false;}return stack.size() == 1;}
}
时间复杂度: O(N):正确的括号组合需要遍历1遍s;
 空间复杂度: O(N):哈希表和栈使用线性的空间大小;