Problem statement
Given a string s of '('
, ')'
and lowercase English characters.
Your task is to remove the minimum number of parentheses ( '('
or ')'
, in any positions) so that the resulting parentheses string is valid and return any valid string.
Formally, a parentheses string is valid if and only if:
- It is the empty string, contains only lowercase characters, or
- It can be written as
AB
(A
concatenated withB
), whereA
andB
are valid strings, or - It can be written as
(A)
, whereA
is a valid string.
Example 1
Input: s = "lee(t(c)o)de)"
Output: "lee(t(c)o)de"
Explanation: "lee(t(co)de)" , "lee(t(c)ode)" would also be accepted.
Example 2
Input: s = "a)b(c)d"
Output: "ab(c)d"
Example 3
Input: s = "))(("
Output: ""
Explanation: An empty string is also valid.
Constraints
1 <= s.length <= 10^5
.s[i]
is either'('
,')'
, or lowercase English letters.
Solution: Stack is a friend
- Construct the result from the valid characters of
s
. - You can use a stack to store the positions of the open brackets
'('
which can be canceled out by later closed ones')'
. - Any remaining
'('
are removed.
Code
#include <iostream>
#include <stack>
using namespace std;
string minRemoveToMakeValid(string s) {
string result;
stack<int> pos;
for (char c: s) {
if (c == ')' && pos.empty() ) {
continue;
}
result += c;
if (c == '(') {
pos.push(result.length() - 1);
} else if (c == ')') {
pos.pop();
}
}
while (!pos.empty()) {
result.erase(result.begin() + pos.top());
pos.pop();
}
return result;
}
int main() {
cout << minRemoveToMakeValid("lee(t(c)o)de)") << endl;
cout << minRemoveToMakeValid("a)b(c)d") << endl;
cout << minRemoveToMakeValid("))((") << endl;
}
Output:
lee(t(c)o)de
ab(c)d
Complexity
- Runtime:
O(N)
, whereN = s.length
. - Extra space:
O(N)
.
Refactorization code
If there are many string::erase()
are performed, the runtime would not be good since the complexity of this function is not constant.
One way to avoid it is constructing the new result from scratch skipping the marked characters.
Code
#include <iostream>
#include <stack>
using namespace std;
string minRemoveToMakeValid(string s) {
{
stack<int> pos;
for (int i = 0; i < s.length(); i++) {
if (s[i] == ')' && pos.empty() ) {
s[i] = '0';
continue;
}
if (s[i] == '(') {
pos.push(i);
} else if (s[i] == ')') {
pos.pop();
}
}
while (!pos.empty()) {
s[pos.top()] = '0';
pos.pop();
}
}
string result;
for (char c : s) {
if (c != '0') {
result += c;
}
}
return result;
}
int main() {
cout << minRemoveToMakeValid("lee(t(c)o)de)") << endl;
cout << minRemoveToMakeValid("a)b(c)d") << endl;
cout << minRemoveToMakeValid("))((") << endl;
}
Output:
lee(t(c)o)de
ab(c)d
Complexity
- Runtime:
O(N)
, whereN = s.length
. - Extra space:
O(N)
.
Implementation notes
- Since
s
contains only characters'('
,')'
or lowercase English letters, you can use any other one to mark the skipped characters. - You can scope a piece of code between the pair
{ ... }
to release some local memory (e.g. the stackpos
) because the variable is destroyed at the end of the scope.