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 →The score rules describe a tree hidden inside the string. A pair of parentheses creates one group; adjacent groups contribute by addition, while a group wrapped around another contributes twice its inside score. You cannot finish an outer group until every group inside it has been evaluated, so the most recently opened unfinished group must be handled first.
Give every opening parenthesis its own running score, initially zero. A closing parenthesis ends the current group: if its inside score is zero, the group is the primitive pair (), worth 1; otherwise its inside score is doubled. Add that finished value to the surrounding group, because adjacent completed groups are combined by addition.
| MEASURE | BOUND | WHY |
|---|---|---|
| Time | O(n) | The loop examines each of the n characters once. Each opening causes one push and each closing causes one pop, constant-time arithmetic, and one addition, so no substring or completed group is scanned again. |
| Space | O(n) | The output is a single integer and is excluded from extra space. The stack stores one entry for each currently open level plus the sentinel; in the worst shape, such as deeply nested parentheses, that is O(n), while shallower input uses less. |
#include <algorithm>
#include <stack>
#include <string>
using namespace std;
class Solution {
public:
int scoreOfParentheses(string s) {
stack<int> st;
st.push(0);
for (char c : s) {
if (c == '(') {
st.push(0);
} else {
int inside = st.top();
st.pop();
int value = max(2 * inside, 1);
st.top() += value;
}
}
return st.top();
}
};The sentinel zero is what makes concatenation work without a special case. For ()(), the first close adds 1 to the sentinel and the second close adds another 1 to the same entry. For (()), the inner close adds 1 to the inner group, and the outer close doubles that result before adding it to the sentinel.
You can avoid the stack because every primitive pair contributes a power of two determined by its nesting depth. When a close follows an opening parenthesis, that pair is exactly (), and its contribution is 2 raised to the depth after the close. A close at depth 0 contributes 1, a close at depth 1 contributes 2, and so on. Other closing parentheses only finish a nonempty group whose contribution was already accounted for by its innermost primitive pairs.
#include <string>
using namespace std;
class Solution {
public:
int scoreOfParentheses(string s) {
int depth = 0;
int score = 0;
for (int i = 0; i < static_cast<int>(s.size()); ++i) {
if (s[i] == '(') {
++depth;
} else {
--depth;
if (s[i - 1] == '(') {
score += 1 << depth;
}
}
}
return score;
}
};This is an optimization, not merely a different arrangement: it reduces extra space from O(n) to O(1), while time remains O(n). The tradeoff is less direct bookkeeping. The stack mirrors the three scoring rules and is easier to adapt if the representation or scoring rules change; the depth version depends on the special power-of-two structure of these parentheses rules.