最长的有效括号 - leetcode
#编程 #go #算法 #leetcode

问题陈述

给出了一个仅包含字符'('and')'的字符串,返回最长有效(良好)括号的长度。

从:https://leetcode.com/problems/longest-valid-parentheses

提取的问题声明

示例1:

Input: s = '(()'
Output: 2
Explanation: The longest valid parentheses substring is '()'.

示例2:

Input: s = ')()())'
Output: 4
Explanation: The longest valid parentheses substring is '()()'.

示例3:

Input: s = ''
Output: 0

约束:

- 0 <= s.length <= 3 * 10^4
- s[i] is '(', or ')'

最长有效括号的解决方案

方法1:蛮力

蛮力方法是生成所有子字符串,并检查每个字符串是否是有效的括号。如果子字符串有效并且长度超过到目前为止所看到的最大长度,请更新最大长度。我们将此最大长度返回为最长的有效括号。

这种方法的问题是 o(n^3)的时间复杂性。将使用三个嵌套的循环。前两个将生成所有子字符串,第三个内部环将验证子字符串是否为有效括号。

方法2:使用堆栈

解决最长有效括号的有效方法是使用堆栈。该解决方案类似于我们在valid parentheses问题中的方法。我们没有将开放式括号(推到堆栈上,而是推开开口支架的索引。

这种方法的算法如下:

- initialize stack<int> st
  // push -1 to the stack to provide the base
  // for the next valid set of parentheses
  st.push(-1)

- set result = 0

- loop for i = 0; i < str.size(); i++
  // if opening bracket, push the index i

  - if str[i] == '('
    - st.push(i)

  - else
    // if str[i] == ')'

    // pop the last encountered opening bracket's index
    - if !st.empty()
      - st.pop()
    - end if

    // if the length formed with the base of the current valid substring
    // is more than max so far
    - if !st.empty
      - set result = max(result, i - st.top())
    - else
      - st.push(i)
    - end if
  - end if
- end for

- return result

该算法的C ++片段如下:

int longestValidParentheses(string s) {
    stack<int> stk;
    stk.push(-1);

    int result = 0;

    for (int i = 0; i < str.size(); i++) {
        if (str[i] == '(') {
            stk.push(i);
        } else {
            if (!stk.empty()) {
                stk.pop();
            }

            if (!stk.empty()) {
                result = max(result, i - stk.top());
            } else {
                stk.push(i);
            }
        }
    }

    return result;
}

这种方法的时间复杂性是 o(n),因为我们一次在字符串上迭代。空间复杂性也是 o(n),因为我们使用了附加的数据结构。

方法3:使用左右计数器

使用两个计数器,我们可以在 o(1)时间中解决此问题。

  • 这个想法是从左到右扫描字符串。

  • 我们使用左右计数器跟踪开放和闭合括号的数量。当识别开放(并关闭)括号时,我们将左右计数器递增1个。

  • 当左右计数器相等时,计算当前子字符串的长度。如果它超过了以前最长的有效括号,我们将使用当前的子字符串长度更新结果。

  • 在扫描时的任何时候,如果右计数器值超过左计数器,则子字符串不是有效的括号字符串。我们将左右计数器设置为0。

  • 我们然后扫描字符串从右向左扫描,并在上方重复类似的步骤。

让我们检查该方法的算法。

算法

- set left, right, maxLength = 0
      n = s.length

- loop for i = 0; i < n; i++
  - if s[i] == '('
    - increment left: left++
  - else
    - increment right: right++
  - end if

  - if left == right
    - update maxLength: maxLength = max(maxLength, 2 * right)
  - else if right > left
    - set left, right = 0, 0
  - end if
- end for

- set left, right = 0, 0

- loop for i = 0; i < n; i++
  - if s[i] == '('
    - increment left: left++
  - else
    - increment right: right++
  - end if

  - if left == right
    - update maxLength: maxLength = max(maxLength, 2 * right)
  - else if left > right
    - set left, right = 0, 0
  - end if
- end for

- return maxLength

上述方法的时间复杂性是 o(n),空间复杂性为 o(1)

c ++ golang javascript 中查看我们的解决方案。

C ++解决方案

class Solution {
public:
    // Main function to return the length of
    // the longest valid parentheses
    int longestValidParentheses(string s) {
        int left = 0, right = 0, maxLength = 0;
        int n = s.length();

        // iterate the string from left to right
        for(int i = 0; i < n; i++) {
            if(s[i] == '(') {
                left++;
            } else {
                right++;
            }

            // if left is equal to right, we found a
            // valid parentheses substring
            if(left == right) {
                maxLength = max(maxLength, 2 * right);
            } else if (right > left) {
                // reset the left and right counter when we have
                // invalid parentheses substring
                left = 0;
                right = 0;
            }
        }

        left = 0;
        right = 0;

        // iterate the string from right to left
        for(int i = n - 1; i >= 0; i--) {
            if(s[i] == '(') {
                left++;
            } else {
                right++;
            }

            // if left is equal to right, we found a
            // valid parentheses substring
            if(left == right) {
                maxLength = max(maxLength, 2 * right);
            } else if (left > right) {
                // reset the left and right counter when we have
                // invalid parentheses substring
                left = 0;
                right = 0;
            }
        }

        return maxLength;
    }
};

Golang解决方案

// Main function to return the length of
// the longest valid parentheses
func longestValidParentheses(s string) int {
    left, right, maxLength := 0, 0, 0
    n := len(s)

    // iterate the string from left to right
    for  i := 0; i < n; i++ {
        if s[i] == '(' {
            left++
        } else {
            right++
        }

        // if left is equal to right, we found a
        // valid parentheses substring
        if left == right {
            maxLength = max(maxLength, 2 * right)
        } else if (right > left) {
            // reset the left and right counter when we have
            // invalid parentheses substring
            left = 0
            right = 0
        }
    }

    left = 0
    right = 0

    // iterate the string from right to left
    for i := n - 1; i >= 0; i-- {
        if s[i] == '(' {
            left++
        } else {
            right++
        }

        // if left is equal to right, we found a
        // valid parentheses substring
        if left == right {
            maxLength = max(maxLength, 2 * right)
        } else if (left > right) {
            // reset the left and right counter when we have
            // invalid parentheses substring
            left = 0
            right = 0
        }
    }

    return maxLength
}

func max(a, b int) int {
    if a > b {
        return a
    }

    return b
}

JavaScript解决方案

// Main function to return the length of
// the longest valid parentheses
var longestValidParentheses = function(s) {
    let left = 0, right = 0, maxLength = 0;
    let n = s.length;

    // iterate the string from left to right
    for(let i = 0; i < n; i++) {
        if(s[i] == '(') {
            left++;
        } else {
            right++;
        }

        // if left is equal to right, we found a
        // valid parentheses substring
        if(left == right) {
            maxLength = Math.max(maxLength, 2 * right);
        } else if (right > left) {
            // reset the left and right counter when we have
            // invalid parentheses substring
            left = 0;
            right = 0;
        }
    }

    left = 0;
    right = 0;

    // iterate the string from right to left
    for(let i = n - 1; i >= 0; i--) {
        if(s[i] == '(') {
            left++;
        } else {
            right++;
        }

        // if left is equal to right, we found a
        // valid parentheses substring
        if(left == right) {
            maxLength = Math.max(maxLength, 2 * right);
        } else if (left > right) {
            // reset the left and right counter when we have
            // invalid parentheses substring
            left = 0;
            right = 0;
        }
    }

    return maxLength;
};

干式运行

让我们干燥运行算法以了解解决方案的工作原理。

Input: s = ')()())'

Step 1: set left = 0, right = 0, maxLength = 0
        n = s.size()
          = 6

Step 2: loop for i = 0; i < n
          0 < 6
          true

          if s[i] == '('
             s[0] == '('
             ')' == '('
             false
          else
            right++
            right = 1

          if left == right
            0 == 1
            false
          else if right > left
            1 > 0
            true

            left = 0
            right = 0

          i++
          i = 1

Step 3: loop for i < n
          1 < 6
          true

          if s[i] == '('
            s[1] == '('
            '(' == '('
            true
            left++
            left = 1

          if left == right
            1 == 0
            false
          else if right > left
            0 > 1
            false

          i++
          i = 2

Step 4: loop for i < n
          2 < 6
          true

          if s[i] == '('
             s[2] == '('
             ')' == '('
             false
          else
            right++
            right = 1

          if left == right
            1 == 1
            true

            maxLength = max(maxLength, 2 * right)
                      = max(0, 2 * 1)
                      = max(0, 2)
                      = 2

          i++
          i = 3

Step 5: loop for i < n
          3 < 6
          true

          if s[i] == '('
            s[3] == '('
            '(' == '('
            true
            left++
            left = 2

          if left == right
            2 == 1
            false
          else if right > left
            1 > 2
            false

          i++
          i = 4

Step 6: loop for i < n
          4 < 6
          true

          if s[i] == '('
             s[4] == '('
             ')' == '('
             false
          else
            right++
            right = 2

          if left == right
            2 == 2
            true

            maxLength = max(maxLength, 2 * right)
                      = max(2, 2 * 2)
                      = max(2, 4)
                      = 4

          i++
          i = 5

Step 7: loop for i < n
          5 < 6
          true

          if s[i] == '('
            s[5] == '('
            ')' == '('
            false
          else
            right++
            right = 3

          if left == right
            2 == 3
            false
          else
            left = 0
            right = 0

          i++
          i = 6

Step 8: loop for i < n
          6 < 6
          false

Step 9: left = 0
        right = 0

Step 10: loop for i = n - 1; i >= 0
           i = 6 - 1 = 5
           i >= 0
           5 >= 0
           true

           if s[i] == '('
             s[5] == '('
             ')' == '('
             false
           else
             right++
             right = 1

           if left == right
             0 == 1
             false
           else if left > right
             0 > 1
             false

           i--
           i = 4

Step 11: loop for i >= 0
           4 >= 0
           true

           if s[i] == '('
             s[4] == '('
             ')' == '('
             false
           else
             right++
             right = 2

           if left == right
             0 == 2
             false
           else if left > right
             0 > 2
             false

           i--
           i = 3

Step 12: loop for i >= 0
           3 >= 0
           true

           if s[i] == '('
             s[3] == '('
             '(' == '('
             true
             left++
             left = 1

           if left == right
             1 == 2
             false
           else if left > right
             1 > 2
             false

          i--
          i = 2

Step 13: loop for i >= 0
           2 >= 0
           true

           if s[i] == '('
             s[2] == '('
             ')' == '('
             false
           else
             right++
             right = 3

           if left == right
             1 == 3
             false
           else if left > right
             1 > 3
             false

           i--
           i = 1

Step 14: loop for i >= 0
           1 >= 0
           true

           if s[i] == '('
             s[1] == '('
             '(' == '('
             true
             left++
             left = 2

           if left == right
             2 == 3
             false
           else if left > right
             2 > 3
             false

           i--
           i = 0

Step 15: loop for i >= 0
           0 >= 0
           true

           if s[i] == '('
             s[1] == '('
             ')' == '('
             false
           else
             right++
             right = 4

           if left == right
             2 == 4
             false
           else if left > right
             2 > 4
             false

           i--
           i = -1

Step 16: loop for i >= 0
           -1 >= 0
           false

Step 17: return maxLength

We return the answer as 4.