持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情
题目描述
2022/10/9 每日一题
输入:给定一个平衡括号字符串 S,按下述规则计算该字符串的分数:
() 得 1 分;AB 得 A + B 分,其中 A 和 B 是平衡括号字符串;(A) 得 2 * A 分,其中 A 是平衡括号字符串。
输出:此平衡括号字符串的按上述规则的得分。
算法思路
方法一:栈中存储字符,遍历到右括号时判断栈顶元素为左括号还是数字
使用for循环遍历字符串:
1、若遍历到左括号,直接入栈
2、若遍历到右括号,将栈顶元素出栈,并判断栈顶元素是左括号还是数字(右括号不会入栈,所以栈中只可能是数字或左括号)
2.1、出栈元素为左括号:将'1'入栈
2.2、出栈元素为数字:持续执行出栈操作并将这些出栈的数字相加,直到出栈元素为左括号,将相加的数字x2并入栈
2.3、继续遍历平衡括号字符串
3、字符串遍历结束:依次出栈栈中元素并相加,返回最后的和。
方法二:栈中存储整型,将每个子式的初始分数设为0并入栈,从里到外计算子式分数并相加
使用for循环遍历字符串:
0、整个字符串当作一个子式,先将整个字符串的初始化分数0入栈
1、若遍历到左括号,代表有新的子式需要计算,则将初始分数0入栈
2、若遍历到右括号,代表一个子式的遍历结束,可以计算此子式的分数
2.1、栈顶元素出栈,比较栈顶元素x2与1之间的最大值,将最大值与二次出栈元素相加,并入栈
理解:
第一次出栈的栈顶元素为可能为0或大于0的数字:
a.若为0,代表这是最底层的一对平衡括号,则分数应置为1,而0 * 2=0,取0,1最大值,此时计为1;
b.若不为0,代表此对括号内还有子式并已计算出分数,此分数*2必大于1,取最大值为子式分数的两倍;
c.二次出栈将当前子式分数叠加到其父子式的分数上。
二次出栈栈顶元素,此元素为当前计算子式的父子式的当前分数:若为0表示当前子式为其父子式的第一个子式,若不为0表示当前子式不是其父子式的第一个子式,则将当前子式的分数叠加到之前的分数上
3、返回栈顶元素
方法三:记录深度来计算分数
每个平衡括号字符串可以变形为2^(deep -1)的和,例如(()((()))(()))可以变形为(())(((())))((())),因此记录每个()的深度然后计算每个()带深度的分数,并将每个()带深度的分数相加,即得最终分数。
代码实现
方法一:
public int scoreOfParentheses(String s) {
Deque<Character> deque = new ArrayDeque<>();
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == '('){
deque.push(s.charAt(i));
}else{
char cur = deque.pop();
if(cur == '('){
deque.push('1');
}else{
int add = cur - '0';
while(deque.peek() != '('){
add += (int)(deque.pop() - '0');
}
deque.pop();
deque.push((char)((add * 2) + '0'));
}
}
}
int ans = 0;
while(deque.peek() != null){
ans += (int)(deque.pop() - '0');
}
return ans;
}
方法二:
public int scoreOfParentheses(String s) {
Deque<Integer> deque = new ArrayDeque<>();
deque.push(0);
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == '('){
deque.push(0);
}else{
int v = deque.pop();
int cur = deque.pop() + Math.max(v * 2, 1);
deque.push(cur);
}
}
return deque.pop();
}
方法三:
public int scoreOfParentheses(String s) {
int dpl = 0;
int ans = 0;
for(int i = 0; i < s.length(); i++){
// 若遍历到左括号则深度加1,遍历到右括号,此右括号一定配对之前的一个左括号,配对的括号需要消除,不计算为深度
dpl += (s.charAt(i) == '(') ? 1 : -1;
// 只有当右括号的前一个字符是左括号时才是遍历到最底层的一对括号,此时才能计算此对括号的分数
// 右括号前是右括号时只是在出前一对括号的深度,而无需计算分数
if(s.charAt(i) == ')' && s.charAt(i - 1) == '('){
ans += 1 << dpl;
}
}
return ans;
}