LeeCode刷题笔记4:最长有效括号

@[TOC](最长有效括号)

题目描述

给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。

示例

在这里插入图片描述

题目链接

计数法

对于字符串从左至右开始遍历,将 '(' 与 ')' 的数量记录下来,当右括号的值大于左括号的值时,那么在它之前那个符号一定匹配成功。所以,此时子串长度为leftCount*2.重置计数器。继续遍历直到遍历完成。

 public int longestValidParentheses(String s) {
        int maxLength = 0;
        int leftCount = 0;
        int rightCount = 0;
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '(')
                leftCount++;
            if (chars[i] == ')')
                rightCount++;
            if (rightCount>leftCount){
                maxLength=Math.max(leftCount*2,maxLength);
                leftCount=0;
                rightCount=0;
            }
        }
        leftCount=Math.min(leftCount,rightCount);
        maxLength=Math.max(leftCount*2,maxLength);
        return maxLength;
    }

在处理如"(()"左括号大于右括号的情况时,我做了 leftCount=Math.min(leftCount,rightCount);的处理,这样可以保证取到较小的数。经过几次测试,完全可以通过诸如"(()"的用例,但是万万没想到.....

在这里插入图片描述

为了解决这个问题,可以倒着遍历一遍。然后在第二遍遍历时将leftCount < rightCount改为leftCount > rightCount,因为倒着遍历相当于把左右括号互换。这个时候就解决了左括号一直大于右括号的情况。最后我还发现了有一个问题没考虑,那就是出现")(())("当一个有效的子串左边被')'围住右边被'('围住时,出现子串长度不被记录的问题,所以我们需要在循环体中加入一条判断if (rightCount==leftCount) maxLength = Math.max(rightCount * 2, maxLength),若写在正序遍历的循环体内其中的rightCount应改为leftCount。

 public static int longestValidParentheses(String s) {
        int maxLength = 0;
        int leftCount = 0;
        int rightCount = 0;
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '(')
                leftCount++;
            if (chars[i] == ')')
                rightCount++;
          if (leftCount < rightCount) {
                maxLength = Math.max(leftCount * 2, maxLength);
                leftCount = 0;
                rightCount = 0;
            }

        }
        leftCount = rightCount = 0;
        for (int i = chars.length - 1; i >= 0; i--) {
            if (chars[i] == '(')
                leftCount++;
            if (chars[i] == ')')
                rightCount++;
            if (leftCount > rightCount) {
                maxLength = Math.max(rightCount * 2, maxLength);
                leftCount = 0;
                rightCount = 0;
            }
            if (rightCount==leftCount)
                maxLength = Math.max(rightCount * 2, maxLength);
        }
        return maxLength;
    }
在这里插入图片描述

在学编译原理时有碰到过括号匹配的问题,一般是用栈来解决。这个问题也一样可以用栈来解决。在栈中存入“(”的下标,然后碰到“)”时就取出,然后计算长度

public  int longestValidParentheses(String s) {
        //栈中保存'('的下标
        int maxLength = 0;
        Deque stack = new LinkedList<>();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.addLast(i);
            } else {
                if (!stack.isEmpty()){
                    int index = stack.pollLast();
                    maxLength = Math.max(maxLength, i - index + 1);
                }
            }
        }
        return maxLength;
    }

然而这不能匹配如"()(())"这种,因为上述代码求出来的是括号的最大深度。
所以还需要进行一定的改变。在栈底保存最后未匹配的")"。当遍历到一个右括号时,取出当前的栈元素,如果取出后如果栈为空了,意味着取出的是一个右括号,这个匹配失败,不需要计算长度。只需要将这个右括号的下标放入栈底,更新栈底元素即可。若取出后不为空,意味着取出的是左括号,这个时候匹配成功,计算长度。注意计算长度应该在弹出栈顶元素之后,然后继续获取一个栈顶元素,用这个新获取的元素来计算长度。若直接用弹出的栈顶元素求则求出的仍然是括号的深度就失去了保存为匹配右括号为下标的意义。对于栈我们应该在初始化时加入一个-1的元素避免出现“()”这种情况导致栈底保存的不是未匹配的最后一个右括号的情况。

 public static int longestValidParentheses2(String s) {
        //栈底保存最后一个没被匹配的")"的下标,其他空间中保存'('的下标
        int maxLength = 0;
        Deque stack = new LinkedList<>();
        stack.push(-1);
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.addLast(i);
            } else {
                stack.pollLast();
                if (!stack.isEmpty()){//匹配成功后,计算长度
                    int index = stack.peekLast();
                    maxLength = Math.max(maxLength, i - index);
                }else {//更新栈底元素
                    stack.addLast(i);
                }
            }
        }
        return maxLength;
    }

你可能感兴趣的:(LeeCode刷题笔记4:最长有效括号)