• LeetCode 笔记系列八 Longest Valid Parentheses [lich你又想多了]


    题目:Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.

      For "(()", the longest valid parentheses substring is "()", which has length = 2.

      Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.

    拿到题目,哎呀,这不是典型的动态规划嘛,然后刷刷开始coding。这道题确实可以用动态规划,但是复杂度就上去了,事实证明也没法通过大集合的测试。不过还是可以当一个DP的练习。如果你比较忙,直接看解法二吧。

    用longestValid[i][j]表示从S串中的字符i到j的最长well-formed表达式的长度;isValid[i][j]表示从i到j是否是一个valid的表达式。

    如何判断longestValid[i][j]的取值呢?有下面几种情况:

    假定有一个maxlength变量。

    1. 如果i='(' 并且 j=')',

      a. 如果j = i+1,那这是一个valid的表达式;

          b. 如果isValid[i+1][j-1]为真,那这也是一个valid表达式;

      c. 对所有在i到j之间的k,如果isValid[i,k]&&isValid[k+1,j]为真,那么这是一个valid表达式,这三种情况maxlength都是i到j的距离;

      d.其他情况,maxlength = longestValid[i][j-1]和 longestValid[i+1][j]比较大的那个。

    2. 如果i='(' 并且 j='(', maxlength等于longestValid[i][j-1]。

    3. 如果i=')' 并且 j=')', maxlength等于longestValid[i+1][j]。

    4. 如果i=')‘ 并且 j='(', maxlength等于longestValid[i-1][j-1].

    判断完成后,longestValid[i][j]赋值于maxlength。

    下面是代码,是不是很复杂很想给博客君一巴掌。

    解法一:

     1 private static int longestValidParentheses(String s) {
     2         // Start typing your Java solution below
     3         // DO NOT write main() function
     4         if(s.length() == 0) return 0;
     5         boolean[][] isValid = new boolean[s.length()][];//isValid[i][j] is true when from i to j, this is a valid parentheses expression
     6         int[][] longestValid = new int[s.length()][];//the longest length of valid expression between i and j
     7         for(int i = 0; i < s.length();i++){
     8             isValid[i] = new boolean[s.length()];
     9             longestValid[i] = new int[s.length()];
    10         }
    11         for(int j = 1; j < s.length();j++){
    12             for(int i = j - 1; i >=0;i--){
    13                 int left = s.charAt(i);
    14                 int right = s.charAt(j);
    15                 int maxLength = 0;
    16                 if(left == '(' && right ==')'){
    17                     if(i + 1 == j) {
    18                         isValid[i][j] = true;
    19                         if(maxLength < 2) maxLength = 2;
    20                     }else {
    21                         if(isValid[i+1][j-1]){
    22                             isValid[i][j] = true;
    23                             if(maxLength < j - i + 1) maxLength = j - i + 1;
    24                         }else if(isValid[i][i+1] && isValid[j-1][j] && 
    25                                 (isValid[i + 2][j - 2] ||  j - i == 3)){
    26                             isValid[i][j]=true;
    27                             if(maxLength < j - i + 1) maxLength = j - i + 1;
    28                         }else {
    29                             maxLength = Math.max(longestValid[i][j-1], longestValid[i+1][j]);
    30                             for(int k = i + 1; k < j;k++){
    31                                 if(isValid[i][k] && isValid[k + 1][j]) {
    32                                     maxLength = j - i + 1;
    33                                     isValid[i][j]=true;
    34                                     break;
    35                                 }
    36                             }
    37                         }
    38                     }
    39                 }else {
    40                     if(left == '(' && right == '(' 
    41                             && longestValid[i][j-1] > maxLength) maxLength = longestValid[i][j-1];
    42                     if(left == ')' && right == ')' 
    43                             && longestValid[i+1][j] > maxLength)maxLength = longestValid[i+1][j];
    44                     if(left ==')' && right == '(' 
    45                             && longestValid[i+1][j-1] > maxLength){
    46                         maxLength = longestValid[i+1][j-1];
    47                     }
    48                 }
    49                 longestValid[i][j] = maxLength;
    50             }
    51         }
    52         return longestValid[0][s.length()-1];
    53     }
    View Code

    plus,这是O(n3)的。。。。“该吃药了。。亲”。如期望的,该解法在大集合的时候超时。

    解法二:来自leetcode讨论组的写法。本来人有O(n)的解法,被楼主活生生地卖弄成了O(n3)。楼主真想挖个坑把自己埋了!!!

    大家首先看,这个解法里面的stack,不是用来存左右括号的。人是来存左括号的index。本来么,右括号也不用存。遍历S。遇到'(',放入lefts。如果遇到')',如果lefts是空,说明这是一个无法匹配的')',记录下last。last里面存放的其实是最后一个无法匹配的')'。为啥要保存这个值呢?主要是为了计算后面完整的表达式的长度。可以这样理解: “所有无法匹配的')'”的index其实都是各个group的分界点。

     1 public static int longestValidParentheses2(String s) {
     2         int maxLen = 0, last = -1;
     3         Stack<Integer> lefts = new Stack<Integer>();
     4         for (int i=0; i<s.length(); ++i) {
     5             if (s.charAt(i)=='(') {
     6                 lefts.push(i);
     7             } else {
     8                 if (lefts.isEmpty()) {
     9                     // no matching left
    10                     last = i;
    11                 } else {
    12                     // find a matching pair
    13                     lefts.pop();
    14                     if (lefts.isEmpty()) {//有一个完整的valid的group。计算该group的长度
    15                         maxLen = Math.max(maxLen, i-last);
    16                     } else {
    17                         //栈内还有‘(',一个最外层完整的group还没有匹配完成,
    18                         //但是通过查询下一个即将匹配还未匹配的"("的index来更新maxLen。
    19                         maxLen = Math.max(maxLen, i-lefts.peek());
    20                     }
    21                 }
    22             }
    23         }
    24         return maxLen;
    25     }
    View Code

    总结下:

    DP不是万能的。注意发现问题的本质。不过这个确实要靠足够的练习。解法二的代码确实很简洁,但是并不是人人都能想到的。

  • 相关阅读:
    8小时外你做什么?下班后的生活决定你的竞争力
    8个月,一位年轻总裁的坠落:值得所有职业经理人深思
    陈紫熹(帮别人名字作诗)
    年轻人创业尤其要注意的五个基本法则
    解密联想20年的45条法则
    小本创业】30条生意妙经及七大关键感悟
    新时代白领必备的两大“新”能力,你有吗?
    秘笈:送给创业者的19条忠告
    C#计算两个日期之间的差
    tnsnames.ora是什么东东?
  • 原文地址:https://www.cnblogs.com/lichen782/p/leetcode_Longest_Valid_Parentheses.html
Copyright © 2020-2023  润新知