LeetCode 32. 最长有效括号 栈解决和动态规划解决 附代码

此题 看着简单,其实挺难的。LeetCode困难题目。常规想法并不能解决
【题目】

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

示例 1:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

【注意】如果栈为空的话,peek会报错,不会返回null。

Stack<Character> stack = new Stack<>();
Character c = stack.peek();

报错

Exception in thread "main" java.util.EmptyStackException
    at java.util.Stack.peek(Stack.java:102)
    at 牛客刷题.LeetCode.栈.longest_valid_parentheses.Solution.longestValidParentheses(Solution.java:21)
    at 牛客刷题.LeetCode.栈.longest_valid_parentheses.Solution.main(Solution.java:11)

原来考虑用栈压入字符’(‘和’)’,发现存在问题,不能讲前面的括号连起来。
比如()((),用下面的做法怎么判断是不是要把第一组括号也算进来呢。如果是这种情况,第三个符号没有对应的右括号了,自然就没有和第一组连起来。
如果以下情况()(()),就要连起来。
解决方法,换一种思路,压入栈的不是单纯的’(‘,这个栈中其实只会压入’(‘,是种浪费。可以压入字符所在的下标,多了下标信息,问题就可以解下去。

package 牛客刷题.LeetCode.栈.longest_valid_parentheses;

import java.util.LinkedList;
import java.util.Stack;

/**
 * Created by Administrator on 2018/5/26 0026.
 */
public class Solution {
    public static void main(String[] args) {
        //String s = "(()()";
        String s = "()(()";
        System.out.println(longestValidParentheses(s));
    }

    public static int longestValidParentheses(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        char[] chars = s.toCharArray();
        int res = 0, max = 0, last = 0;
        Stack<Character> stack = new Stack<>();
        for (int i =0; i < chars.length; i++) {
            if (chars[i] == '(' ) {
                if (stack.size() == 0) {
                    last = max;
                }
                stack.push('(');
            } else {
                if (stack.size() != 0 && stack.peek() == '('){
                    last++;
                    max = last;
                    stack.pop();
                } else {
                    last = 0;
                }
                res = Math.max(res, max);
                max = 0;
            }
        }
        return res * 2;
    }
}

写的代码在(()()测试用例下出错

对应输出应该为:

4

你的输出为:

2

原因是我在考虑局部的括号组的时候没有吧相连的括号考虑进来。
不光在stack为空的时候,要和前面的括号组连起来。
相邻的括号组要直接连起来的。

public static int longestValidParentheses(String s) {
        char[] chars = s.toCharArray();
        LinkedList<Integer> stack = new LinkedList<>();
        int start = 0;
        int res = 0;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '(') {
                stack.push(i);
            } else {
                if (stack.size() == 0) {
                    start = i + 1;
                } else if (stack.size() == 1){
                    stack.pop();
                    res = Math.max(res, i - start + 1);
                } else {
                    res = Math.max(res, i - stack.pop() +1);
                }
            }
        }
        return res;
    }

注:
这道题用动态规划解也可以
dp[i]是以chars[i-1]字符为结尾,能组成的最大括号组合数。
dp[i+1]根据char[i]的具体的括号类型得来,递推详见代码。
如果字符是'('dp[i+1]为0。
如果字符是')' 根据chars[i-1]是左还是右括号分情况讨论
注意如果配对了,要考虑配对前面的括号组合连起来的。代码很容易出错。
详情看代码longestValidParentheses()方法。

package 牛客刷题.LeetCode.栈.longest_valid_parentheses;

import java.util.LinkedList;
import java.util.Stack;

/**
 * Created by Administrator on 2018/5/26 0026.
 */
public class Solution {
    public static void main(String[] args) {
        System.out.println(longestValidParentheses("(()()")); //4
        System.out.println(longestValidParentheses("()(()")); //2
        System.out.println(longestValidParentheses("((())()")); //6
        System.out.println(longestValidParentheses("())")); //2
        System.out.println(longestValidParentheses("()(())")); //6
    }

    //错误的解法
    public static int longestValidParentheses1(String s) {
        if(s==null || s.length()==0)
            return 0;
        LinkedList<Integer> stack = new LinkedList<Integer>();
        int start = 0;
        int max = 0;
        for(int i=0;i<s.length();i++)
        {
            if(s.charAt(i)=='(')
            {
                stack.push(i);
            }
            else
            {
                if(stack.isEmpty())
                {
                    start = i+1;
                }
                else
                {
                    stack.pop();
                    max = stack.isEmpty()?Math.max(max,i-start+1): Math.max(max,i-stack.peek());
                }
            }
        }
        return max;
    }

    //考虑动态规划方法
    public static int longestValidParentheses(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        char[] chars = s.toCharArray();
        int[] dp = new int[s.length() + 1];
        int max = 0;
        dp[0] = 0;
        dp[1] = 0;
        for (int i = 1; i < s.length(); i++) {
            if (chars[i] == ')') {
                if (chars[i-1] == '(') {
                    dp[i+1] = dp[i-1] + 2;
                } else {
                    if (i-dp[i] -1 >= 0 && chars[i - dp[i] -1] == '(') {
                        dp[i + 1] = dp[i] + 2 + dp[i- dp[i] -1];
                    } else {
                        dp[i+1] = 0;
                    }
                }
            } else {
                dp[i+1] = 0;
            }
            max = Math.max(max, dp[i+1]);
        }
        return max;
    }

    //栈的解法,存入下标
    public static int longestValidParentheses2(String s) {
        char[] chars = s.toCharArray();
        LinkedList<Integer> stack = new LinkedList<>();
        int start = 0;
        int res = 0;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '(') {
                stack.push(i);
            } else {
                if (stack.size() == 0) {
                    start = i + 1;
                } else if (stack.size() == 1){
                    stack.pop();
                    res = Math.max(res, i - start + 1);
                } else {
                    stack.pop();
                    res = Math.max(res, i - stack.peek());
                }
            }
        }
        return res;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值