括号的分数 图解题解
这道题到底在问什么
- 输入
- S = "()"
- 输出
- 1 (一对空括号)
- 输入
- S = "(())"
- 输出
- 2 (里面 1 分,外面包一层翻倍)
- 输入
- S = "()()"
- 输出
- 2 (两对并排,1 加 1)
先想最直接的笨办法
开始之前,先在栈底放一个 0。这个 0 代表「最外面一层」当前的累计分数,所有算出来的分最终都会汇总到它身上。上方一排是要依次处理的 8 个括号,我们从最左边开始,一个一个扫。(动画第 4 步)
最优解:一步一步想明白
- 3记牢「左括号压 0 开新层、右括号结算栈顶(空层得 1、否则翻倍)、把分数加回外层」,下面每一帧都在套它。
- 4开始之前,先在栈底放一个 0。这个 0 代表「最外面一层」当前的累计分数,所有算出来的分最终都会汇总到它身上。上方一排是要依次处理的 8 个括号,我们从最左边开始,一个一个扫。
- 5扫到第 1 个字符,是左括号 (。它代表「进入更里面的一层」。我们的做法是往栈里压入一个 0,给这新的一层先记 0 分,等里面的东西算完再结算。
- 6压进一个 0。现在栈顶这个 0 就是「刚进入的这一层」的累计分数,它暂时是 0,因为里面还没算出任何东西。栈一旦变长,就说明我们钻进了更深的括号里。
- 7扫到第 2 个字符,是左括号 (。它代表「进入更里面的一层」。我们的做法是往栈里压入一个 0,给这新的一层先记 0 分,等里面的东西算完再结算。
- 8压进一个 0。现在栈顶这个 0 就是「刚进入的这一层」的累计分数,它暂时是 0,因为里面还没算出任何东西。栈一旦变长,就说明我们钻进了更深的括号里。
- 9扫到第 3 个字符,是右括号 )。它代表「当前这一层到此封口、可以结算了」。接下来把栈顶那层的分数弹出来,看看这层到底值多少分。
- 10把栈顶弹出来,这层封口前累计的分数是 v = 0。它是 0,意味着这一层从压进来到现在什么分都没加过,也就是一对紧挨着的空括号 ()。
- 11v 是 0,说明这就是一对空括号 (),按规则 () 得 1 分。把这 1 分加到新的栈顶,也就是它外面那一层。外层分数从此多了 1。
- 12扫到第 4 个字符,是左括号 (。它代表「进入更里面的一层」。我们的做法是往栈里压入一个 0,给这新的一层先记 0 分,等里面的东西算完再结算。
- 13压进一个 0。现在栈顶这个 0 就是「刚进入的这一层」的累计分数,它暂时是 0,因为里面还没算出任何东西。栈一旦变长,就说明我们钻进了更深的括号里。
- 14扫到第 5 个字符,是左括号 (。它代表「进入更里面的一层」。我们的做法是往栈里压入一个 0,给这新的一层先记 0 分,等里面的东西算完再结算。
- 15压进一个 0。现在栈顶这个 0 就是「刚进入的这一层」的累计分数,它暂时是 0,因为里面还没算出任何东西。栈一旦变长,就说明我们钻进了更深的括号里。
- 16扫到第 6 个字符,是右括号 )。它代表「当前这一层到此封口、可以结算了」。接下来把栈顶那层的分数弹出来,看看这层到底值多少分。
- 17把栈顶弹出来,这层封口前累计的分数是 v = 0。它是 0,意味着这一层从压进来到现在什么分都没加过,也就是一对紧挨着的空括号 ()。
- 18v 是 0,说明这就是一对空括号 (),按规则 () 得 1 分。把这 1 分加到新的栈顶,也就是它外面那一层。外层分数从此多了 1。
- 19扫到第 7 个字符,是右括号 )。它代表「当前这一层到此封口、可以结算了」。接下来把栈顶那层的分数弹出来,看看这层到底值多少分。
- 20把栈顶弹出来,这层封口前累计的分数是 v = 1。它大于 0,意味着这一层里面已经包着别的括号、攒了 1 分。
- 21v 是 1 不为 0,说明里面包着东西,按规则 (A) 要翻倍:2 乘 1 等于 2。把 2 加到新的栈顶,也就是外面那一层。外层分数从此多了 2。
- 22扫到第 8 个字符,是右括号 )。它代表「当前这一层到此封口、可以结算了」。接下来把栈顶那层的分数弹出来,看看这层到底值多少分。
- 23把栈顶弹出来,这层封口前累计的分数是 v = 3。它大于 0,意味着这一层里面已经包着别的括号、攒了 3 分。
- 24v 是 3 不为 0,说明里面包着东西,按规则 (A) 要翻倍:2 乘 3 等于 6。把 6 加到新的栈顶,也就是外面那一层。外层分数从此多了 6。
- 258 个括号全部处理完,栈里只剩栈底这一个数 6。它就是最外层汇总到的全部分数,也就是整串的总分。把过程连起来看:最里面两对 () 各得 1,被层层括号包着不断翻倍累加,最终汇成 6。
⚠️ 容易写错的地方
✗ 错:把 (A) 算成 A 加 1
✓ 对:(A) 是把里面的分数翻倍,得 2 倍 A,不是加 1
嵌套一层是乘 2,只有一对空括号 () 才是 1 分
✗ 错:忘了 AB 并排要相加
✓ 对:同一层里有多对括号,各自的分数要全部加起来
规则 AB 得 A 加 B,栈里靠「加到外层」自然实现
✗ 错:不放栈底那个 0,结算时弹空栈
✓ 对:一开始就在栈底压一个 0 占位,代表最外层
没有这个 0,最外层的分数无处累加,还会弹空栈出错
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def scoreOfParentheses(self, s: str) -> int:
ans = d = 0
for i, c in enumerate(s):
if c == '(':
d += 1
else:
d -= 1
if s[i - 1] == '(':
ans += 1 << d
return ansC++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
int scoreOfParentheses(string s) {
int ans = 0, d = 0;
for (int i = 0; i < s.size(); ++i) {
if (s[i] == '(') {
++d;
} else {
--d;
if (s[i - 1] == '(') {
ans += 1 << d;
}
}
}
return ans;
}
};Java
import java.util.*;
class Solution {
public int scoreOfParentheses(String s) {
int ans = 0, d = 0;
for (int i = 0; i < s.length(); ++i) {
if (s.charAt(i) == '(') {
++d;
} else {
--d;
if (s.charAt(i - 1) == '(') {
ans += 1 << d;
}
}
}
return ans;
}
}复杂度
时间
O(n)
n 为括号个数,从左到右只扫一遍,每个字符做常数次操作
空间
O(n) / O(1)
动画的分数栈最坏存 O(n) 层;参考代码的深度计数法只用一个变量 d,空间 O(1)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 括号的分数 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
除了用栈,还有更省空间的写法吗?+
有,就是参考代码用的「深度计数法」。不用栈,只用一个变量 d 记当前嵌套深度:遇左括号 d 加一,遇右括号 d 减一。每遇到一对最里层的空括号 (),就给答案加上 2 的 d 次方。因为每对 () 自身值 1,外面每包一层翻一倍,包在第 d 层就贡献 2 的 d 次方。这样空间只要 O(1),时间还是一遍 O(n)。栈的写法更直观,深度计数法更省。
为什么分数栈的栈底要先放一个 0?+
那个 0 代表「最外面一层」的累计分数。所有内层算出来的分,最后都要加到它身上。如果不放这个占位的 0,当最外层的右括号封口、要把分数加回外层时,栈就空了,没地方加,程序还会因为弹空栈出错。放一个 0 当地基,整套累加就顺了。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 括号的分数 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。