算法通关村第四关——括号匹配问题的解决

80 阅读2分钟

1.括号匹配问题

对应leetcode20. 有效的括号

遇到这样的问题我们脑海中肯定是怎么判断括号是成对成对的出现的,如果所有的括号都能满足成对出现,那么问题就迎刃而解了;

如何判断一个字符串中括号是否是成对出现的呢?

我们可以创建一个Map, 其中 key为 '(' , '{' , '[' ; 而value为 ')' , ' } ' , ' ] ';

同时创建一个栈,用来存放左括号,想一想这样的场景,如果一个左括号出现的位置在第一个,如果括号成对的话,那么右括号一定在最后一个位置 ; 比如说 '({[ ]})' , 可以看出 ' ( ' 出现的最早,而 ' ) ' 出现的最晚;而栈的特点是先进后出, 由于第一个字符' ( ' 最先入栈,那么只有当 ' [ ' , '{' 这两个符号都出栈时,' ( ' 才能出栈,很符合解决这道题目;

解题思路:我们只需要将字符串 str 从前往后遍历,同时将所有的左括号入栈,遇到右括号就出栈,比较出栈元素和当前遍历到的字符是否是成对的,如果出现一个括号不成对出现,直接返回 false 即可;如果遍历到字符串的结尾,同时栈中元素也为空,那么就返回 true ;

代码如下:

public static boolean isValidSign(String str) {
    if (str.length() == 1) {
        return false;
    }
    // map中记录的是成对的括号
    Map<Character, Character> map = new HashMap<>();
    map.put('(', ')');
    map.put('{', '}');
    map.put('[', ']');
    Stack<Character> stack = new Stack<>();
    char[] chars = str.toCharArray();
    // 开始遍历字符串
    for (char ch : chars) {
        // 如果为左括号,入栈即可
        if (ch == '(' || ch == '{' || ch == '[') {
            stack.push(ch);
        } else { // 如果是右括号,那么需要先判断栈是否为空,如果栈为空,那么说明肯定有括号无法成对出现
            if (!stack.isEmpty()) {
                // 左括号出栈,同时利用map中的记录来获取当前左括号所对应的另一半,如果map.get(c)!= 遍历到的字符ch;
                // 那么直接返回false,有括号不能成对;
                char c = stack.pop();
                if (ch == ')' || ch == ']' || ch == '}' && map.get(c) != ch) {
                    return false;
                }
            } else { // 栈为空,直接返回false;
                return false;
            }
        }
    }
    // 如果字符串遍历结束,如果所有括号都成对出现,那么栈一定为空;否则字符串中有不成对括号出现;
    return stack.isEmpty();
}

这种方法的时间复杂度对我们解决这道题来说已经足够了,但在翻看leetcode评论的时候,发现了更优解;

没有使用map记录成对的括号,直接一个栈,一次遍历,几个判断直接搞定;

但是思路有点变化,如果当前来到的字符是左括号,那么我们手动把对应的右括号入栈,如果遍历到右括号时,直接判断栈中元素和当前右括号是否相等即可

public static boolean isValidBestMethod(String s) {
    if (s.isEmpty()) {
        return true;
    }
    Stack<Character> stack = new Stack<>();
    for (Character c : s.toCharArray()) {
        // 如果当前字符是左括号
        if (c == '(') {  
            stack.push(')');
        } else if (c == '{') {
            stack.push('}');
        } else if (c == '[') {
            stack.push(']');
            // 如果当前字符是右括号,就判断栈是否为空,如果栈不为空,那么栈顶元素和当前字符是否一致,两个条件都满足
            // 则说明括号成对,否则返回false即可;
        } else if (stack.isEmpty() || c != stack.pop()) {
            return false;
        }
    }
    return stack.isEmpty();
}

我只能说声这种思路还是挺牛逼的,时间复杂度上减少了常数级别的判断,以及初始化map时的消耗,直接打败 98% 的人;