zoukankan      html  css  js  c++  java
  • 0032. Longest Valid Parentheses (H)

    Longest Valid Parentheses (H)

    题目

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

    Example 1:

    Input: "(()"
    Output: 2
    Explanation: The longest valid parentheses substring is "()"
    

    Example 2:

    Input: "(()"
    Output: 2
    Explanation: The longest valid parentheses substring is "()"
    

    题意

    给定一个只包含左右括号的字符串,输出连续匹配括号对的最长长度。

    思路

    个人想到的方法是压栈法:建两个栈,一个par存括号字符,另一个index存括号字符对应的下标。用i遍历字符串,如果为'(',则同时压入两个栈;若为')',此时如果par为空,则压入par和index,如果par非空且栈顶元素为'(',说明配对成功,同时出栈par和index,而此时index的栈顶元素(非空时)代表的是当前最右边无法匹配的括号的下标,那么 i - index.peek() (index非空)/ i + 1 (index为空) 就代表了新增一对匹配括号对后更新的连续匹配长度,将之与max比较并更新max。
    官方的压栈法解答只使用了一个栈,但整体思路是一样的。

    左右扫描法:设两个计数器left和right,先从左向右扫描字符串,'('则left+1,')'则right+1,每扫描一个字符串,比较left和right,如果left < right,则将left和right重置,如果left == right,则更新max;同理再从右向左扫描,如果left > right,则将left和right重置,如果left == right,则更新max。
    这是因为左右扫描,不能正确处理"( ) ( ( ( ) )"这种情况,而右左扫描可以;右左扫描不能正确处理"( ( ) ) ) ( )"这种情况,但左右扫描可以。

    动态规划:dp数组记录以当前括号字符为结尾的最大有效长度,显而易见只有以')'为结尾才可能形成有效字符串,因此只有在当前字符为')'时才进行处理,共可能会有以下两种情况:

    1. s[i] == ')' && s[i - 1] == '(',这时很容易得到 (dp[i] = dp[i - 2] + 2)
    2. s[i] == ')' && s[i - 1] == ')',这种情况下,先找到以s[i - 1]为结尾的有效字符串开头的前一个字符c (当然如果dp[i - 1] == 0,就不需要找这个c了),如果c为'(',则与s[i]构成匹配括号对,同时还要考虑以c前一个字符c'为结尾的有效字符串的长度 (举个例子,"( ) ( ( ) )",最后一个')'为s[i]),最终得到 (dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2])

    代码实现

    Java

    压栈法

    class Solution {
        public int longestValidParentheses(String s) {
            int max = 0;
    
            Deque<Character> par = new ArrayDeque<>();
            Deque<Integer> index = new ArrayDeque<>();
    
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (c == '(') {
                    par.push(c);
                    index.push(i);
                } else {
                    if (par.isEmpty() || par.peek() != '(') {
                        par.push(c);
                        index.push(i);
                    } else {
                        par.pop();
                        index.pop();
                        max = Math.max(max, index.isEmpty() ? i + 1 : i - index.peek());
                    }
                }
            }
    
            return max;
        }
    }
    
    class Solution {
        public int longestValidParentheses(String s) {
            int max = 0;
    
            Deque<Integer> stack = new ArrayDeque<>();
            stack.push(-1);
    
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (c == '(') {
                    stack.push(i);
                } else {
                    stack.pop();
                    // 出栈后若栈空,说明出栈的是不匹配的')',将当前')'压入栈
                    // 若栈非空,说明出栈的是匹配的'(',更新max
                    if (stack.isEmpty()) {
                        stack.push(i);
                    } else {
                        max = Math.max(max, i - stack.peek());
                    }
                }
            }
            
            return max;
        }
    }
    

    左右扫描法

    class Solution {
        public int longestValidParentheses(String s) {
            int max = 0;
            int left = 0, right = 0;
    
            for (int i = 0; i < s.length(); i++) {
                char c = s.charAt(i);
                if (c == '(') {
                    left++;
                } else {
                    right++;
                }
                if (left == right) {
                    max = Math.max(max, left + right);
                } else if (left < right) {
                    left = right = 0;
                }
            }
    
            left = right = 0;
            for (int i = s.length() - 1; i >= 0; i--) {
                char c = s.charAt(i);
                if (c == '(') {
                    left++;
                } else {
                    right++;
                }
                if (left == right) {
                    max = Math.max(max, left + right);
                } else if (left > right) {
                    left = right = 0;
                }
            }
            
            return max;
        }
    }
    

    动态规划

    class Solution {
        public int longestValidParentheses(String s) {
            int max = 0;
    
            int[] dp = new int[s.length()];
            for (int i = 1; i < s.length(); i++) {
                if (s.charAt(i) == ')') {
                    if (s.charAt(i - 1) == '(') {
                        dp[i] = i - 2 >= 0 ? dp[i - 2] + 2 : 2;
                    } else {
                        if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                            dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0);
                        }
                    }
                }
            }
            
            for (int i = 0; i < s.length(); i++) {
                max = Math.max(max, dp[i]);
            }
    
            return max;
        }
    }
    

    JavaScript

    压栈法

    /**
     * @param {string} s
     * @return {number}
     */
    var longestValidParentheses = function (s) {
      let max = 0
      let stack = []
      for (let i = 0; i < s.length; i++) {
        if (s[i] === '(' || stack.length === 0 || s[stack[stack.length - 1]] === ')') {
          stack.push(i)
        } else {
          stack.pop()
          max = Math.max(max, i - (stack.length === 0 ? -1 : stack[stack.length - 1]))
        }
      }
      return max
    }
    

    左右扫描法

    /**
     * @param {string} s
     * @return {number}
     */
    var longestValidParentheses = function (s) {
      return Math.max(scan(s.split(''), true), scan(s.split('').reverse(), false))
    }
    
    let scan = function (s, flag) {
      let left = 0, right = 0
      let max = 0
      for (let p of s) {
        if (p === '(') {
          left++
        } else {
          right++
        }
        if (left === right) {
          max = Math.max(max, left + right)
        } else if (flag ? left < right : left > right) {
          left = right = 0
        }
      }
      return max
    }
    

    动态规划

    /**
     * @param {string} s
     * @return {number}
     */
    var longestValidParentheses = function (s) {
      let max = 0
      let dp = new Array(s.length).fill(0)
    
      for (let i = 1; i < s.length; i++) {
        if (s[i] === ')') {
          if (s[i - 1] === '(') {
            dp[i] = i > 1 ? dp[i - 2] + 2 : 2
          } else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] === '(') {
            dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0)
          }
          max = Math.max(max, dp[i])
        }
      }
    
      return max
    }
    
  • 相关阅读:
    第60天Shader法线贴图、切线空间
    第59天Shader基本光照模型、漫反射光照算法、光照计算、高光、灰度图实现
    第58天shader混合命令、颜色运算、顶点/片元着色、属性类型、语义、坐标空间、Unity内置矩阵、纹理采样、Cg函数
    第57天shader基本结构、渲染队列、裁剪、深度写入
    第55天XLua实现背包
    第54天XLua插件使用(续)
    第53天XLua插件使用
    第52天-lua语言基础语法
    第51天-AssetBundle(AB包)
    第50天-背包实例(三)
  • 原文地址:https://www.cnblogs.com/mapoos/p/13190972.html
Copyright © 2011-2022 走看看