• 32.Longest Valid Parentheses---dp


    题目链接:https://leetcode.com/problems/longest-valid-parentheses/description/

    题目大意:找出最长的括号匹配的子串长度。例子:"(()("长度是2;"()()(())"长度是8

    解法一:利用三层for循环,逐一的找每一个子串,并判断每一个子串是否是括号匹配的。很遗憾,超时了。代码如下:

     1     public int longestValidParentheses(String s) {
     2         int res = 0;
     3         for(int i = 0; i < s.length(); i++) {//逐一查看每一个子串
     4             for(int j = i + 2; j <= s.length(); j += 2) {
     5                 int cnt = parentheses(s.substring(i, j));
     6                 if(res < cnt) {
     7                     res = cnt;
     8                 }
     9             }
    10         }
    11         return res;
    12     }
    13     //判断是否是括号匹配的
    14     public static int parentheses(String s) {
    15         Stack<Character> st = new Stack<Character>();
    16         int cnt = 0;
    17         for(int i = 0; i < s.length(); i++) {
    18             char c = s.charAt(i);
    19             if(c == ')') {
    20                 if(!st.isEmpty() && st.peek() == '(') {
    21                     cnt++;
    22                     st.pop();
    23                 }
    24                 else {
    25                     return 0;
    26                 }
    27             }
    28             else {
    29                 st.push(c);
    30             }
    31         }
    32         if(!st.isEmpty()) {
    33             return 0;
    34         }
    35         return cnt * 2;
    36     }
    View Code

     解法二(借鉴):用栈存储左括号下标,而不是'('左括号。如果是'(',则将下标压栈。如果是')',则查看栈的情况,如果栈空,则记录下一个子串开始的位置下标(即i+1);如果非空,则查看栈中元素情况,如果只有一个'(',则弹出计数子串长度,如果有多个'(',则计数到目前为止的匹配的子串长度情况。或者同时压栈存储左括号和右括号下标,当遇到')',则查看栈顶元素,如果是'(',则计数,否则压栈。这两种方法都是o(n)的时间复杂度。代码如下(耗时26ms):

    第一种压栈左括号下标的方法:

     1 public int longestValidParentheses(String s) {
     2         Stack<Integer> st = new Stack<Integer>();//存'('下标
     3         int res = 0, lastIndex = 0, length = s.length();
     4         for(int i = 0; i < length; i++) {
     5             char c = s.charAt(i);
     6             if(c == '(') {//如果是'(',将下标压栈
     7                 st.push(i);
     8             }
     9             else {//如果是')',分情况讨论
    10                 if(st.isEmpty()) {//如果为空,则出现')'没有'('匹配的情况,则当前子串结束,下一个子串的开始位置即是当前子串结束的下一个位置
    11                     lastIndex = i + 1;
    12                 }
    13                 else {//如果非空,可能出现两种情况:'()'或'(())'
    14                     st.pop();
    15                     if(st.isEmpty()) {//如果为空,则说明栈中没有'('需要匹配
    16                         res = Math.max(res, i - lastIndex + 1);
    17                     }
    18                     else {//如果非空,则当前栈中还有'('存在
    19                         res = Math.max(res, i - st.peek());
    20                     }
    21                 }
    22             }
    23         }
    24         return res;
    25     }
    View Code

    第二种压栈左括号和右括号下标的方法(基本与上面第一种一样):

     1     public int longestValidParentheses(String s) {
     2         Stack<Integer> st = new Stack<Integer>();
     3         int res = 0, length = s.length();
     4         for(int i = 0; i < length; i++) {
     5             if(s.charAt(i) == '(') {//左括号压栈下标
     6                 st.push(i);
     7             }
     8             else {//遇到右括号
     9                 if(st.isEmpty()) {//如果栈空,则压栈右括号下标
    10                     st.push(i);
    11                 }
    12                 else {
    13                     if(s.charAt(st.peek())== '(') {//如果栈顶元素是左括号,则匹配,退栈计数子串长度
    14                         st.pop();
    15                         res = Math.max(res, (i - (st.isEmpty() ? -1 : st.peek())));
    16                     }
    17                     else {//如果栈顶元素是右括号,则压栈右括号下标
    18                         st.push(i);
    19                     }
    20                 }
    21             }
    22         }
    23         return res;
    24     }
    View Code

    解法三:利用dp。首先dp[i] 表示从s[i]往前推最长能匹配的子串,换句话说,就是到s[i]为止的最长匹配子串后缀。那么当对于下面几种情况进行分析:

    1. s[i] ==’(’     s[i]为左括号,dp[i]=0这个很好理解。
    2. s[i] ==’)’  这就要分情况了
      a) 如果s[i-1]是’(’说明已经完成了一次匹配,子串长度为2,但是还要加上dp[i-2]的大小,也就是当前匹配的这对括号前面的最长匹配长度,它们是相连的。
      b) 如果s[i-1]是’)’这样不能匹配,则需要考虑s[i-1-dp[i-1]]的情况了,如果s[i-1-dp[i-1]]是一个左括号,则与当前右括号匹配,那么此时我们令dp[i]=dp[i-1]+2,这个2就是刚刚匹配的左右括号。最后还要把dp[i-2-dp[i-1]](即与当前括号')'匹配的'('前面一个位置的dp长度,它们是相连的)值加起来,把相连的最大长度求出来。代码如下(耗时20ms):

     1     public int longestValidParentheses(String s) {
     2         int length = s.length();
     3         int[] dp = new int[length];
     4         int res = 0;
     5         for(int i = 0; i < length; i++) {
     6             dp[i] = 0;
     7             if(s.charAt(i) == ')' && (i - 1) >= 0) {
     8                 if((i - 1) >= 0 && s.charAt(i - 1) == '(') {//如果前一个位置与当前括号')'匹配
     9                     dp[i] = 2;//暂且只计算匹配的'('')'
    10                     if(i - 2 >= 0) {//加上与')'匹配的'('前一个位置的dp匹配长度
    11                         dp[i] += dp[i - 2];
    12                     }
    13                 }
    14                 else {//如果前一个位置与当前括号'('不匹配
    15                     if((i - 1 - dp[i - 1]) >= 0 && s.charAt(i - 1 - dp[i - 1]) == '(') {//查看【前一个位置下标-匹配数】之后的字符与当前括号')'是否匹配
    16                         dp[i] = dp[i - 1] + 2;//如果匹配,则在前一个位置匹配数的情况下+2,即加上刚与当前')'匹配的左右括号数量
    17                         if(i - 2 - dp[i - 1] >= 0) {//加上与')'匹配的'('前一个位置的dp匹配长度
    18                             dp[i] += dp[i - 2 - dp[i - 1]];
    19                         }
    20                     }
    21                 }
    22             }
    23             res = Math.max(res, dp[i]);
    24         }
    25         return res;
    26     }
    View Code
  • 相关阅读:
    ThinkPHP教程_PHP框架之ThinkPHP(三)【系统常量与模板替换】
    ThinkPHP教程_PHP框架之ThinkPHP(二)【URL路径访问与模块控制器、URL四种模式、PATHINFO的两种模式、模板与控制器之间的关系】
    ThinkPHP教程_PHP框架之ThinkPHP(一)【入门和介绍、ThinkPHP版本和文件夹规范、项目入口文件】
    Markdown,技术简历编辑的一缕清风...
    Zend Studio 13.5的安装、破解和汉化
    原生JS配合AJAX完成省市县三级联动(带数据库、PHP+Smarty)
    DAL与数据库类型的对应关系
    mysql 学习
    关于MySQL的分区(partion)
    Response.Write,Page.RegisterClientScriptBlock和Page.RegisterStartupScript的区别
  • 原文地址:https://www.cnblogs.com/cing/p/8206893.html
Copyright © 2020-2023  润新知