Opening the reading…
Opening the reading…
STACK › PARENTHESES PROBLEM
Open — the attempt gate is not wired up yet
This editorial is meant to unlock after you have run the problem at least once, with the worked solution behind one further deliberate click. That needs per-learner unlock state nothing stores today, so for now the whole article is open.
Try it yourself first →A valid parentheses string has two directional requirements. Reading from left to right, no prefix may contain more closing parentheses than opening parentheses, because a closing parenthesis needs an earlier opening parenthesis. Reading from right to left, no suffix may contain more opening parentheses than closing parentheses, because an opening parenthesis needs a later closing parenthesis.
An unlocked position can help either requirement. During the left-to-right scan, pretend every unlocked position is an opening parenthesis, because that gives the prefix as much protection as possible against a locked closing parenthesis. During the right-to-left scan, pretend every unlocked position is a closing parenthesis for the symmetric reason. If either favorable scan still becomes impossible, no assignment can repair it. With even length, these two checks also ensure that the flexible positions can be assigned consistently.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | The algorithm examines each position once in each of two scans. Each examination performs constant work, so the total number of operations is 2n plus constant checks, which is O(n). |
| Space | O(1) extra | Only the length and one running balance are stored; the input strings are not copied and the two scans do not retain positions. The bound stays O(1) even for the worst input shape, and there is no returned collection whose storage needs to be counted. |
#include <string>
using namespace std;
class Solution {
public:
bool canBeValid(string s, string locked) {
int n = static_cast<int>(s.size());
if (n % 2 != 0) {
return false;
}
int balance = 0;
for (int i = 0; i < n; ++i) {
if (locked[i] == '0' || s[i] == '(') {
++balance;
} else {
--balance;
}
if (balance < 0) {
return false;
}
}
balance = 0;
for (int i = n - 1; i >= 0; --i) {
if (locked[i] == '0' || s[i] == ')') {
++balance;
} else {
--balance;
}
if (balance < 0) {
return false;
}
}
return true;
}
};The two conditions inside the scans deliberately differ. In the first loop, an unlocked position contributes as '(', since that is the choice that best protects a prefix. In the second loop, the same position contributes as ')', since that is the choice that best protects a suffix. The negative check is the important placement: it rejects the moment a direction has run out of possible matches, rather than waiting until the scan ends.