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 →Scan the string from left to right while tracking how many open parentheses are currently available to match a closing parenthesis. An open parenthesis increases that supply. A closing parenthesis consumes one if possible; otherwise it has no earlier partner, so you must insert an open parenthesis before it. That insertion is forced, and it fixes exactly one unmatched close.
After the scan, any open parentheses still in the balance have never found a closing partner. Each one requires one inserted close after it or at a suitable later position. Therefore the answer has two independent parts: insertions forced while scanning for unmatched closes, plus insertions needed for opens left over at the end. No insertion can fix two unmatched parentheses, so this count is minimum.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | The loop reads each of the n characters once and performs a constant amount of work for each character, so no character contributes to the running time more than once. |
| Space | O(1) extra | Only the two integer counters are maintained. The input string and the required returned integer are not working storage, and there is no shape of input that increases this bound. |
#include <string>
using namespace std;
class Solution {
public:
int minAddToMakeValid(string s) {
int open = 0, close = 0;
for (char c : s) {
if (c == '(') {
open++;
} else {
if (open > 0) {
open--;
} else {
close++;
}
}
}
return open + close;
}
};The important placement is the open > 0 check before decrementing. A closing parenthesis can match only an opening parenthesis that appeared earlier and remains unused. If none exists, increasing close records the one insertion that must occur; at the end, open records the opposite repair. The algorithm never needs to construct the repaired string because only the number of forced insertions matters.
A stack can model the same process more literally: push every '(', and pop when a ')' has an available match. If the stack is empty for a ')', count an inserted '('. The stack left at the end represents unmatched opens, so its size is added to the count. This is a reasonable version when you want to preserve unmatched characters, but it is not an optimisation: it uses O(n) extra space instead of O(1).
#include <stack>
#include <string>
using namespace std;
class Solution {
public:
int minAddToMakeValid(string s) {
stack<char> unmatchedOpen;
int insertions = 0;
for (char c : s) {
if (c == '(') {
unmatchedOpen.push(c);
} else if (!unmatchedOpen.empty()) {
unmatchedOpen.pop();
} else {
insertions++;
}
}
return insertions + static_cast<int>(unmatchedOpen.size());
}
};