Longest `subsequence` of balanced parentheses

折月煮酒 提交于 2019-12-06 19:56:27

Since someone else posted an answer, here is a O(n) answer to the single query with O(1) space. Keep the count of parens balanced and pointers to the last open and last closed paren. Until you've run off the string, scan forward on the last open to find another open paren. Then scan forward from the max of the last open and last closed paren to find the next closed paren. If you find a pair that way, increment the count of parens balanced. When you reach the end of the string, you will have the correct count, even though you paired up the parens incorrectly.

There may actually be multiple maximal subsequences of balanced parens. But if you take any maximal subsequence of balanced parens, and replace every open paren with the left-most possible open paren, and then every close paren with the left-most possible open parens, the result will be the ones you found. (Proof left as an instructive exercise to the reader.)

Here is pseudo-code.

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.

And next we have the challenge of many range queries. It turns out that making this fast takes O(n) precomputation and O(n) space, and each range query will be O(log(n)) time.

Here is the hint for that problem. Suppose that we have 2 blocks A and B right next to each other. Each of which internally has some number of balanced subsequence of parens, some number of additional open parens available to the right, and some number of additional close parens available to the left. Then the combined block C has the following:

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)

I leave to you the exercise of figuring out what set of blocks to precompute to be able to compute any block in time O(log(n)).

I will describe an O(n) solution

First, we have an dp[n] array, for each position i , if i is the close bracket ), dp[i] will store the farthest position, which make a valid sequence of parentheses that ends at i.

We maintain a stack , which keep track of open brackets and their position. So if we encounter an open bracket, we put it into the stack together with its location, and if we encounter an close bracket, we pop the last open bracket out, and update the dp array.

  • dp[i] = min (position of open bracket, dp[position of open bracket - 1] ), this will check if before the open bracket, is there an close bracket, if yes, we improve the dp[i]

So, the answer will be the largest value between i - dp[i]

Java code:

    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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!