`

Leetcode - Longest Valid Parentheses

阅读更多

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.

[balabala]  自己只想出来DP包装的枚举实现,妥妥地超时。网上搜到了巧妙的解答,好好吸其精华。

 

public class Solution {
    // method 4: O(n)
    // dp[i]: 包含s.charAt[i - 1]的最长有效括号串长度
    // 所有'('对应的dp[i] == 0
    // 位置i - 1处为')' 时,若前面有匹配的'(', 其位置记为leftPos,  
    // dp[i]=当下(...)长度 + leftPos前一个位置处的最长有效括号串长 
    public int longestValidParentheses(String s) {
        if (s == null || s.length() < 2)
            return 0;
        int N = s.length();
        int[] dp = new int[N + 1];
        LinkedList<Integer> stack = new LinkedList<Integer>();
        int max = 0;
        for (int i = 1; i <= N; i++) {
            char c = s.charAt(i - 1);
            if (c == '(') {
                stack.push(i);
            } else if (!stack.isEmpty()){
                int leftPos = stack.pop();
                dp[i] = i - leftPos + 1 + dp[leftPos - 1];
                max = Math.max(max, dp[i]);
            }
        }
        return max;
    }
    // method 3: O(n)
    // dp[i]表示从索引i到结尾的字符串的前缀的最长有效括号对长度
    // http://www.cnblogs.com/huntfor/p/3886111.html
    // 计算方向:自右向左
    public int longestValidParentheses3(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int[] dp = new int[n];
        dp[n - 1] = 0;
        int max = 0;
        for (int i = n - 2; i >= 0; i--) {
            if (s.charAt(i) == '(') {
                int j = i + 1 + dp[i + 1]; //寻找最长有效前缀的后驱
                if (j < n && s.charAt(j) == ')') {
                    dp[i] = dp[i + 1] + 2;
                    if (j + 1 < n)
                        dp[i] += dp[j + 1];
                }
                max = Math.max(max, dp[i]);
            }
        }
        return max;
    }
    
    // method 2: O(n)
    // http://www.cnblogs.com/lichen782/p/leetcode_Longest_Valid_Parentheses.html
    // http://blog.csdn.net/worldwindjp/article/details/39460161
    // 实现中的last变量记录的是有效串开始位置的前面一个下标,
    // 也是最后一个无法匹配的')'的下标,每个无法匹配的')'是一组组有效串的分界点
    public int longestValidParentheses(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int max = 0;
        int last = -1; 
        LinkedList<Integer> stack = new LinkedList<Integer>();// 栈中元素是每个入栈'(' 的下标
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                if (stack.isEmpty()) {
                    last = i; // 遇到')'且无人匹配,更新last为当前下标
                } else {
                    stack.pop();
                    if (!stack.isEmpty()) {
                        max = Math.max(max, i - stack.peek());
                    } else {
                        max = Math.max(max, i - last);
                    }
                }
            }
        }
        return max;
    }
    // method 1 : 枚举,O(n^3), 超时
    // dp[i][j] : tells whether s.substring(i, j) is a valid parentheses string
    public int longestValidParentheses1(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        // 预处理 - 不顶用, 通过分析算法的时间复杂度可知是杯水车薪。
        StringBuilder sb = new StringBuilder(s);
        int beg = 0;
        int end = s.length() - 1;
        for (int i = beg; i <= end; i++) {
            if (s.charAt(i) == ')')
                beg++;
            else
                break;
        }
        
        for (int i = end; i >= beg; i--) {
            if (s.charAt(i) == '(')
                end--;
            else
                break;
        }
        s = s.substring(beg, end + 1);
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        // 长度为奇数的子串不可能平衡, 无需计算
        // for (int i = 0; i < n; i++) {
        //     for (int j = i; j < n; j += 2) {
        //         dp[i][j] = false;
        //     }
        // }
        // 判断所有长度为2的子串
        for (int i = 0; i < n - 1; i++) {
            dp[i][i + 1] = s.charAt(i) == '(' && s.charAt(i + 1) == ')';
        }
        // 从小到大依次判断其他长度的子串, O(n^3)
        for (int len = 4; len <= n; len += 2) { // O(n)
            for (int i = 0; i < n - len + 1; i++) { // O(n)
                int j = i + len - 1;
                dp[i][j] = s.charAt(i) == '(' && s.charAt(j) == ')' && dp[i + 1][j - 1];
                for (int k = i + 1; k < j - 1; k += 2) { // O(n)
                    dp[i][j] |= dp[i][k] && dp[k + 1][j];
                }
            }
        }
        // 逆推,找到最长平衡串
        for (int len = n; len >= 2; len -= 2) {
            for (int i = 0; i < n - len + 1; i++) {
                int j = i + len - 1;
                if (dp[i][j])
                    return len;
            }
        }
        return 0;
    }
}

 

分享到:
评论
2 楼 likesky3 2015-04-22  
DP还是没有理解到家吧,我的观念是DP能通过存储中间过程减少计算量,没想到它在这题中却是最复杂的。做完题目一定要有分析时间复杂度的意识,这样可以及时转换思路。原来method1的思想是贪婪啊,我没有意识到,是不是贪婪通常比DP简单,但是不一定全局最优?
1 楼 qb_2008 2015-04-21  
我想问题在于这道题不是DP,因为哪个左括号和哪个右括号匹配是固定的,你可以用一个栈
模拟(method 2),也可以用一个贪婪(method 1)。这种匹配或贪婪写得好就是O(n),
因为只需要找到每个右括号匹配的左括号。method 1 的时间复杂度是O(n3),因为多了
Line 96和Line 100的两个循环。
如果开始能尝试几个简单的例子,就会发现匹配是固定的,避免用复杂度较高的DP。不过
DP确实很适合这类匹配情况,不管三七二十一,用上DP,都不会做错

相关推荐

    C语言-leetcode题解之32-longest-valid-parentheses.c

    其中,编号为32的题目"longest-valid-parentheses"是一个关于字符串处理的经典问题,要求编写代码找出给定的括号字符串中最长的有效括号子串长度。 在解决"longest-valid-parentheses"问题时,需要理解有效括号子串...

    java-leetcode题解之Longest Valid Parentheses.java

    其中,“Longest Valid Parentheses”是一道在LeetCode上常见的算法题目,要求编写一个函数来找出输入字符串中有效的括号配对的最大长度。 在Java中,解决这类问题通常需要对字符串进行遍历,并且利用栈、动态规划...

    js-leetcode题解之32-longest-valid-parentheses.js

    本文是一篇专注于解决LeetCode平台中JavaScript语言编写的“32-最长有效括号”问题的题解文章。在介绍解题思路和实现方法之前,先对这个问题进行详细阐述。问题要求编写一个函数,该函数能够找到给定字符串中合法的...

    _leetcode-python.pdf

    - Valid Parentheses: 验证给定的字符串中的括号是否有效。这通常可以通过栈结构来实现。 - Merge Two Sorted Lists: 合并两个有序链表。 - Generate Parentheses: 生成所有可能的有效的括号组合。 - Merge k Sorted...

    颜色分类leetcode-leetcode-[removed]我对Leetcode问题的解决方案

    颜色分类leetcode My Leetcode Problems Solutions Using javascript(ES6) 1 Two Sum 两数之和 5 Longest Palindromic Substring 最长回文子串 7 Reverse Integer 整数反转 9 Palindrome Number 回文数 11 Container...

    gasstationleetcode-leetcode-rust:莱特代码休息

    加油站 leetcode 力码锈 问题 # 标题 命令 1 cargo run ...3-longest-substring-without-repeating-...20-valid-parentheses 21 cargo run --bin 21-merge-two-sorted-lists 27 cargo run --bin 27-remove-element 28

    leetcode卡-Array-LeetCode-Solution:数组-LeetCode-解决方案

    比如"有效的括号"(Valid Parentheses)问题,可以使用栈来检查括号配对的有效性。 3. **双指针法**:在数组中使用两个指针同时移动,常用于查找中间元素、解决区间问题等。如"寻找旋转排序数组中的最小值"(Find ...

    javalruleetcode-leetcode-java:力码笔记

    Parentheses 26.Remove Duplicates from Sorted Array 53.Maximum Subarray 70.Climbing Stairs 121.Best Time to Buy and Sell Stock 122.Best Time to Buy and Sell Stock II 123.Best Time to Buy and Sell Stock...

    javalruleetcode-learn-algorithms::laptop:Java实现的各种算法题解

    java lru leetcode ...Parentheses](./leetcode/动态规划-Longest Valid Parentheses.java) [动态规划-Maximum Length of Repeated Subarray](./leetcode/动态规划-Maximum Length of Repeated Subar

    leetcode卡-LeetCode-HashTable:此存储库包含HashTable探索卡中所有问题的解决方案

    3. **集合操作**:如“有效的括号”(Valid Parentheses),哈希表可以用于存储未闭合的括号,以便检查括号匹配性。 4. **最近点对**:在“最接近的三数之和”(3Sum Closest)问题中,双指针配合哈希表可以快速...

    Leetcode-best-DSA-问题:必须执行这些leetcode编码问题以提高您的问题解决能力

    比如“有效的括号”(Valid Parentheses)使用栈来检查括号的正确性,而“用队列实现栈”(Implement Queue using Stacks)则展示了它们的灵活应用。 3. **堆**:最大堆和最小堆常用于优先队列和优化问题。例如,...

    javalruleetcode-LeetCode::lollipop:个人LeetCode习题解答仓库-多语言

    java lru leetcode :ice_cream: LeetCode ...Parentheses 26 Remove Duplicates from Sorted Array 48 Rotate Image 53 Maximum Subarray 55 Jump Game 56 Merge Intervals 64 Minimum Path Sum 73

    丢失的最小正整数leetcode-LeetCodePractice:我的LeetCode练习

    Longest Common Prefix:这道题和大家思路一样,都是取第一个字符串里的字节与后面的进行比较,只是要注意,针对空vector的返回,针对vector只有一个值时候的返回,和一些通过设置更好初始值进行优化。 20. Valid ...

    Leetcode-note:刷题笔记

    "有效的括号"(Valid Parentheses)则涉及到了栈的应用。 五、持续学习与提升 1. 学习社区:参与LeetCode社区讨论,查看他人的解题思路,可以拓宽视野,提高问题解决能力。 2. 定期复习:定期回顾做过的题目,加深...

    LeetCode-Java

    二叉树问题如"Binary Tree Inorder Traversal",链表问题如"Reverse Linked List",栈的应用如"Valid Parentheses",哈希表的使用则常见于查找和去重问题。 3. **排序和搜索**:快速排序、归并排序、二分查找等是...

    leetcode2-Algorithms-Practice:创建此repo是为了跟踪我在解决问题方面的进展

    Longest Common Prefix 运行时间:40 毫秒内存使用:13.9 MB 20. Valid Parentheses 运行时间:40 毫秒内存使用:13.8 MB 22. Generate Parentheses 运行时间:164 毫秒内存使用:22.5 MB 26. Remove Duplicates ...

    LeetCode最全代码

    # [LeetCode](https://leetcode.com/problemset/algorithms/) ![Language](https://img.shields.io/badge/language-Python%20%2F%20C++%2011-orange.svg) [![License]...

    leetcode中国-leetcode:leetcode刷题

    Parentheses 用栈判断括号匹配 Regular Expression Matching 递归匹配 wildcard matching 动态规划 longest common prefix , 简单 valid number, hard, 用有限自动机 integer to roman ,easy , 模拟 roman to ...

    leetcode530-algorithm:算法

    leetcode 530 ** LeetCode 题目更新 ** 用来记录业余时间所做的算法题目,保持对于数据结构的熟悉。 ** ...Valid Parentheses 022 Generate Parentheses 028 Implement strStr() 031 Next Permutat

Global site tag (gtag.js) - Google Analytics