有效的括号[简单]

有效的括号[简单]_第1张图片>优质博文: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 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):正确的括号组合需要遍历1s
空间复杂度: O(N):哈希表和栈使用线性的空间大小;

你可能感兴趣的:(算法题,spring,后端,面试,职场和发展,java,算法,性能优化)