平衡括号的最长`子序列'

时间:2014-10-30 01:46:29

标签: algorithm dynamic-programming parentheses

我正在尝试解决前面提到的problem变体:

  

给定一串括号(长度&lt; = 1,000,000)和一个列表   范围查询,找到平衡的最长子序列   <= 100,000的每个范围内的每个范围内的括号   查询

我发现这个other SO问题类似,但只有O(N ^ 3)算法。

我认为dp[i, j] = longest balanced subsequence in [i .. j]形式的DP解决方案应该有效,因为一旦计算完毕,这将使得仅通过查询DP表就能够回答所有范围查询。但是,即使是这个问题的O(N ^ 2)解决方案也会超出时间限制,因为输入字符串长度很大。

此外,使用堆栈跟踪匹配括号的技巧不再直接起作用,因为您正在寻找子序列,而不是子串。

我有一种方法,我认为可能有效,但我不确定:

区间内平衡括号的最长子序列的长度是该区间内平衡括号的最长非重叠子串的长度之和。

例如,如果您有字符串

  

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

     

) ) ( ( ) ( ( ) ) ) ) ( ( ) )

区间[0,8](包括)中平衡括号的最长子序列的长度为5.此长度等于区间内最长非重叠子串长度之和的长度:& #34;()&#34; +&#34;(())&#34;。

这种方法总能持有,还是有更好的方法?

2 个答案:

答案 0 :(得分:4)

由于其他人发布了答案,因此这是O(n)个问题的O(1)parens = 0 last_open = 0 last_closed = 0 while last_open < len(str) && last_closed < len(str): if str[last_open] == ')': # We are looking for the next open paren. last_open += 1 elif last_closed < last_open: # Start our search for a last closed after the current char last_closed = last_open + 1 elif str[last_closed] == '(': # still looking for a close pair last_closed += 1 else: # We found a matching pair. parens += 1 last_open += 1 # and now parens has the correct answer. 答案。保持平衡的数量和指向最后打开和最后关闭的paren。直到你用完字符串,在最后一次打开时向前扫描以找到另一个打开的paren。然后从最后一个打开和最后一个关闭的paren的最大值向前扫描,找到下一个关闭的paren。如果你找到一对那样,增加平衡的数量。当你到达字符串的末尾时,即使你错误地配对了parens,你也会有正确的计数。

平衡的parens实际上可能存在多个最大子序列。但是如果你采取平衡的parens的任何最大子序列,并用最左边可能的开放paren替换每个开放的paren,然后用最左边可能的开放parens替换每个关闭的paren,结果将是你找到的那些。 (证明留给读者作为指导性练习。)

这是伪代码。

O(n)

接下来我们遇到了许多范围查询的挑战。事实证明,快速执行O(n)预计算和O(log(n))空间,每个范围查询都需要C.balanced = A.balanced + B.balanced + min(A.open, B.close) C.open = B.open + max(A.open - B.close, 0) C.close = A.close + max(B.close - A.open, 0) 时间。

以下是该问题的提示。假设我们有2个块A和B紧挨着。每个内部都有一些平衡的parens子序列,右边有一些额外的开放式parens,左边有一些额外的紧密的parens。然后组合块C具有以下内容:

O(log(n))

我向您介绍了预先计算出哪些块可以计算任何块的时间{{1}}。

答案 1 :(得分:1)

我将描述一个O(n)解决方案

首先,我们有一个dp[n]数组,对于每个职位i,如果i是近距离)dp[i]将存储最远的位置,使得有效的括号序列以i结束。

我们维持一个堆栈,跟踪开放式括号及其位置。因此,如果我们遇到一个开括号,我们将它与其位置一起放入堆栈中,如果我们遇到一个紧括号,我们会弹出最后一个开括号,并更新dp数组。

  • dp[i] = min (position of open bracket, dp[position of open bracket - 1] ),这会检查是否在开括号之前,是否有一个近距离括号,如果是,我们会改进dp[i]

因此,答案将是i - dp[i]

之间的最大值

Java代码:

    public static void main(String[] args) {
    String val = "))(()(())))(())";// Which store the parentheses sequence
    int[] dp = new int[val.length()];
    Arrays.fill(dp, -1);

    Stack<Integer> stack = new Stack();
    for (int i = 0; i < val.length(); i++) {
        char c = val.charAt(i);
        if (c == '(')
            stack.push(i);
        else if (!stack.isEmpty()) {
            int v = stack.pop();
            dp[i] = v;
            if (v > 0 && val.charAt(v - 1) == ')')
                if (dp[v - 1] != -1)
                    dp[i] = dp[v - 1];
        }
    }
    int result = 0;
    for (int i = 0; i < val.length(); i++){
        if (dp[i] != -1){
            System.out.println(val.substring(dp[i] , i + 1));

            result = Math.max(result, i - dp[i] + 1);
        }
    }
    System.out.println(result);
}

Out put:

()
()
()(())
(()(()))
()
(())
8