LeetCode 32. Longest Valid Parentheses 找到最长的符合规则的括号的数量

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: 4
Explanation: The longest valid parentheses substring is "()()"

Example 3:

Input:"()(()"

Output:2

Explanation: The longest valid parentheses substring is "()"


Approach 1: Brute Force

判断每一个非空偶数长度子串是否符合括号规则,暴力搜索。

Example:
"((())"

(( --> invalid
(( --> invalid
() --> valid, length=2
)) --> invalid
((()--> invalid
(())--> valid, length=4
maxlength=4
public class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<Character>();
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push('(');
            } else if (!stack.empty() && stack.peek() == '(') {
                stack.pop();
            } else {
                return false;
            }
        }
        return stack.empty();
    }
    public int longestValidParentheses(String s) {
        int maxlen = 0;
        for (int i = 0; i < s.length(); i++) {
            for (int j = i + 2; j <= s.length(); j+=2) {
                if (isValid(s.substring(i, j))) {
                    maxlen = Math.max(maxlen, j - i);
                }
            }
        }
        return maxlen;
    }
}

Complexity Analysis

  • Time complexity : O(n^3). Generating every possible substring from a string of length nn requires O(n^2). Checking validity of a string of length nn requires O(n).

  • Space complexity : O(n). A stack of depth nn will be required for the longest substring. 


Approach 2: Using Dynamic Programming

Algorithm

This problem can be solved by using Dynamic Programming. We make use of a dp array where iith element of dp represents the length of the longest valid substring ending at iith index. We initialize the complete \text{dp}dp array with 0's. Now, it's obvious that the valid substrings must end with ‘)’. This further leads to the conclusion that the substrings ending with ‘(’ will always contain '0' at their corresponding dp indices. Thus, we update the dp array only when ‘)’ is encountered.

To fill dp array we will check every two consecutive characters of the string and if

The reason behind this is that if the 2nd last ‘)’ was a part of a valid substring (say sub_ssub​s​​), for the last ‘)’ to be a part of a larger substring, there must be a corresponding starting ‘(’ which lies before the valid substring of which the 2nd last ‘)’ is a part (i.e. before sub_ssub​s​​). Thus, if the character before sub_ssub​s​​ happens to be ‘(’, we update the dp[i] as an addition of 22 in the length of sub_ssub​s​​ which is dp[i−1]. To this, we also add the length of the valid substring just before the term "(,sub_s,)" , i.e. dp[i−dp[i−1]−2].

For better understanding of this method, see this example:

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

Runtime: 8 ms

Complexity Analysis

  • Time complexity : O(n). Single traversal of string to fill dp array is done.

  • Space complexity : O(n). dp array of size nn is used. 


Approach 3: Using Stack 在栈中保存字符序号

Algorithm

Instead of finding every possible string and checking its validity, we can make use of stack while scanning the given string to check if the string scanned so far is valid, and also the length of the longest valid string. In order to do so, we start by pushing −1 onto the stack.

For every ‘(’ encountered, we push its index onto the stack.

For every ‘)’ encountered, we pop the topmost element and subtract the current element's index from the top element of the stack, which gives the length of the currently encountered valid string of parentheses. If while popping the element, the stack becomes empty, we push the current element's index onto the stack.(即遇到')'的话,首先从栈中弹出一个元素,接着判断弹出元素后的栈是否为空,如果为空则将当前')'的序号压入栈;如果不为空,则用当前‘)’的序号减去当前栈顶的值得到的值就是当前的最长有效长度) In this way, we keep on calculating the lengths of the valid substrings, and return the length of the longest valid string at the end.

See this example for better understanding.

class Solution {
public:
	int longestValidParentheses(string s) {
		int maxans = 0;
		stack<int> si;
		si.push(-1);
		for (int i = 0; i < s.length(); ++i) {
			if (s[i] == '(')
				si.push(i);
			if (s[i] == ')') {
				si.pop();
				if (si.empty()) {
					si.push(i);
				}
				else {
					maxans = max(maxans, i - si.top());
				}
			}
		}
		return maxans;
	}
};

Runtime: 8 ms

Complexity Analysis

  • Time complexity : O(n). nn is the length of the given string..

  • Space complexity : O(n). The size of stack can go up to n. 


Approach 4: Without extra space

Algorithm

In this approach, we make use of two counters left and right. First, we start traversing the string from the left towards the right and for every ‘(’ encountered, we increment the left counter and for every ‘)’ encountered, we increment the right counter. Whenever left becomes equal to rightright, we calculate the length of the current valid string and keep track of maximum length substring found so far. If right becomes greater than left we reset left and right to 0.

Next, we start traversing the string from right to left and similar procedure is applied.

Example of this approach:

class Solution {
public:
	int longestValidParentheses(string s) {
		int maxans = 0,left = 0,right = 0;
		for (int i = 0; i < s.length(); ++i) {
			if (s.at(i) == '(') {
				++left;
			}
			else {
				++right;
			}

			if (left == right) {
				maxans = max(maxans, 2 * right);
			}
			else if (right >= left) {
				left = right = 0;
			}
		}
		left = right = 0;
		for (int i = s.length() - 1; i >= 0; --i) {
			if (s.at(i) == '(') {
				++left;
			}
			else {
				++right;
			}
			if (left == right) {
				maxans = max(maxans, 2 * left);
			}
			else if (left >= right) {
				left = right = 0;
			}
		}
		return maxans;
	}
};

Complexity Analysis

  • Time complexity : O(n). Two traversals of the string.

  • Space complexity : O(1). Only two extra variables leftleft and rightright are needed.

猜你喜欢

转载自blog.csdn.net/qq_25800311/article/details/82710847