news 2026/5/14 6:14:28

算法题 括号的分数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法题 括号的分数

856. 括号的分数

问题描述

给定一个平衡括号字符串s,按下述规则计算该字符串的分数:

  • ()得 1 分
  • ABA + B分,其中AB是平衡括号字符串
  • (A)2 * A分,其中A是平衡括号字符串

返回字符串s的分数。

示例

输入:"()"输出:1
输入:"(())"输出:2解释:(())=2*()=2*1=2
输入:"()()"输出:2解释:()()=()+()=1+1=2
输入:"(()(()))"输出:6解释:(()(()))=2*(()+(()))=2*(1+2)=6

算法思路

深度优先搜索 + 栈模拟

  1. 核心

    • 平衡括号字符串可以递归分解
    • 每个()贡献的分数 = 2^(深度)
  2. 方法一:递归

    • 遍历字符串,找到每个独立的平衡子串
    • 对每个子串递归计算分数
    • 合并结果:独立子串相加,嵌套子串乘以2
  3. 方法二:深度计算

    • 遍历字符串,维护当前深度
    • 遇到()时,贡献分数为 2^depth
    • 每个()的实际贡献等于它所在深度的2的幂次
  4. 方法三:栈模拟

    • 使用栈存储当前各层的分数
    • 遇到(时压入0
    • 遇到)时,计算当前层分数并更新上一层

代码实现

方法一:递归

classSolution{/** * 递归计算括号字符串的分数 * 将字符串分解为独立的平衡子串,分别计算后相加 * * @param s 平衡括号字符串 * @return 字符串的分数 */publicintscoreOfParentheses(Strings){returnscore(s,0,s.length()-1);}/** * 计算子串s[start...end]的分数 */privateintscore(Strings,intstart,intend){// 基础情况:最简单的"()"得1分if(end-start==1){return1;}intbalance=0;// 平衡计数器inttotalScore=0;// 找到独立的平衡子串并分别计算for(inti=start;i<=end;i++){if(s.charAt(i)=='('){balance++;}else{balance--;}// 当balance为0时,找到了一个独立的平衡子串if(balance==0){if(i==end){// 整个字符串是一个嵌套结构:(A)// 分数 = 2 * score(A)totalScore=2*score(s,start+1,end-1);}else{// 当前子串是独立的:AB 形式// 分数 = score(A) + score(B)totalScore+=score(s,start,i);// 递归处理剩余部分totalScore+=score(s,i+1,end);break;// 已经分解完成}}}returntotalScore;}}

方法二:深度计算

classSolution{/** * 深度计算 * 每个"()"的贡献是2^depth,其中depth是其嵌套深度 * * @param s 平衡括号字符串 * @return 字符串的分数 */publicintscoreOfParentheses(Strings){intdepth=0;// 当前嵌套深度inttotalScore=0;// 总分数for(inti=0;i<s.length();i++){if(s.charAt(i)=='('){depth++;}else{depth--;// 如果前一个字符是'(',说明遇到了"()"if(s.charAt(i-1)=='('){// 贡献分数为2^depthtotalScore+=(1<<depth);// 位运算:1 << depth = 2^depth}}}returntotalScore;}}

方法三:栈模拟

importjava.util.*;classSolution{/** * 使用栈模拟计算括号分数 * 栈中存储当前各层的累计分数 * * @param s 平衡括号字符串 * @return 字符串的分数 */publicintscoreOfParentheses(Strings){Stack<Integer>stack=newStack<>();stack.push(0);// 初始化栈底为0for(charc:s.toCharArray()){if(c=='('){// 遇到左括号,压入0表示新层开始stack.push(0);}else{// 遇到右括号,计算当前层的分数intcurrentScore=stack.pop();// 当前层的分数intparentScore=stack.pop();// 父层的分数// 如果currentScore为0,说明是"()",得1分// 否则是嵌套结构,得2 * currentScore分intlayerScore=currentScore==0?1:2*currentScore;// 将当前层分数加到父层stack.push(parentScore+layerScore);}}// 栈中只剩最终结果returnstack.pop();}}

算法分析

  • 方法一时间复杂度:O(n²)
    • 最坏情况下每次递归都要遍历整个子串
    • 例如:(((((...)))))这样的完全嵌套结构
  • 方法二时间复杂度:O(n)
    • 只需要一次遍历
    • 位运算操作是O(1)
  • 方法三时间复杂度:O(n)
    • 每个字符最多入栈出栈一次
  • 空间复杂度
    • 方法一:O(n)(递归栈)
    • 方法二:O(1)
    • 方法三:O(n)(显式栈)

算法过程

1:s = "(()(()))"

方法二

s: ( ( ) ( ( ) ) ) i: 0 1 2 3 4 5 6 7
  1. i=0(depth=1
  2. i=1(depth=2
  3. i=2)depth=1,前一个字符是(,所以totalScore += 2^1 = 2
  4. i=3(depth=2
  5. i=4(depth=3
  6. i=5)depth=2,前一个字符是(,所以totalScore += 2^2 = 4
  7. i=6)depth=1,前一个字符是),不加分
  8. i=7)depth=0,前一个字符是),不加分

结果totalScore = 2 + 4 = 6

方法三

初始: stack = [0] ( : stack = [0, 0] ( : stack = [0, 0, 0] ) : pop 0, pop 0 → 0==0 → push 0+1 = [0, 1] ( : stack = [0, 1, 0] ( : stack = [0, 1, 0, 0] ) : pop 0, pop 0 → 0==0 → push 0+1 = [0, 1, 1] ) : pop 1, pop 1 → 1!=0 → push 1+2*1 = [0, 3] ) : pop 3, pop 0 → 3!=0 → push 0+2*3 = [6] 结果: 6

测试用例

publicclassMain{publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:基础情况System.out.println("Test 1: "+solution.scoreOfParentheses("()"));// 1// 测试用例2:嵌套System.out.println("Test 2: "+solution.scoreOfParentheses("(())"));// 2// 测试用例3:并列System.out.println("Test 3: "+solution.scoreOfParentheses("()()"));// 2// 测试用例4:复杂嵌套System.out.println("Test 4: "+solution.scoreOfParentheses("(()(()))"));// 6// 测试用例5:深度嵌套System.out.println("Test 5: "+solution.scoreOfParentheses("((()))"));// 4// ((())) = 2 * (2 * ()) = 2 * 2 * 1 = 4// 测试用例6:混合结构System.out.println("Test 6: "+solution.scoreOfParentheses("()(())"));// 3// ()(()) = 1 + 2 = 3// 测试用例7:更复杂System.out.println("Test 7: "+solution.scoreOfParentheses("(()()())"));// 6// (()()()) = 2 * (1 + 1 + 1) = 6// 测试用例8:最大深度System.out.println("Test 8: "+solution.scoreOfParentheses("((((()))))"));// 16// 2^4 = 16// 测试用例9:单层多并列System.out.println("Test 9: "+solution.scoreOfParentheses("()()()()"));// 4// 测试用例10:嵌套和并列混合System.out.println("Test 10: "+solution.scoreOfParentheses("((())(()))"));// 8// ((())(())) = 2 * (2 + 2) = 8}}

关键点

  1. 深度贡献

    • 每个()的实际贡献是2^depth
    • 每嵌套一层,外层的括号会将内层分数乘以2
  2. 识别()

    • 在遍历时,如果当前字符是)且前一个字符是(,说明遇到了基础的()
  3. 位运算

    • 1 << depthMath.pow(2, depth)更高效
    • 位运算在底层执行更快

常见问题

  1. 为什么每个()的贡献是 2^depth?
    每层外层括号都会将内层分数乘以2。例如,深度为2的()会被外层两层括号分别乘以2,总共乘以4=2²。

  2. 方法二如何处理()()这种并列情况?
    每个()都会被独立识别和计算。第一个()在深度0时贡献1,第二个()也在深度0时贡献1,总共2。

  3. 栈中的初始0?
    初始0作为根节点的分数,确保所有计算都有父层可以累加。最终栈中只剩这个累加后的总分数。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/14 6:14:27

Java计算机毕设之基于JavaWeb的校园招聘管理系统高校校园招聘信息服务系统 (完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/14 6:13:05

温度影响精度?高精度模拟量采集模块适配攻略来了

高精度模拟量采集模块的核心功能是将温度、湿度、压力、电流等物理量转换为标准模拟信号(如4-20mA、0-10V)并精准采集&#xff0c;其应用环境温度直接影响采集精度、稳定性和使用寿命。一、应用场景 高精度模拟量采集模块的应用环境温度需与模块自身工作温度范围匹配&#xff0…

作者头像 李华
网站建设 2026/5/1 4:17:42

ERP企业资源管理系统代码(Java)

1. 仓库管理模块物料分类&#xff1a;采用ABC/XYZ多维分类法&#xff0c;结合物料属性与消耗规律&#xff0c;建立动态管理档案。追溯管控&#xff1a;通过条码/RFID技术实现全生命周期追溯&#xff0c;支持批次号与保质期管理。作业优化&#xff1a;WMS系统智能分配库位&#…

作者头像 李华
网站建设 2026/5/11 10:24:29

领导力准则——面试的隐形钥匙

在亚马逊的SDE-Test面试中&#xff0c;技术技能固然重要&#xff0c;但领导力准则&#xff08;Leadership Principles, LP&#xff09;往往成为决定成败的“重中之重”。作为软件测试从业者&#xff0c;您可能精通自动化测试或缺陷追踪&#xff0c;却忽略了LP在面试中的战略性地…

作者头像 李华
网站建设 2026/5/7 8:03:19

谈谈你的离职原因?这样回答既诚实又加分

离职原因背后的职业态度 在软件测试领域&#xff0c;离职原因的回答不仅体现职业素养&#xff0c;更映射测试人员特有的质量保障思维。根据2025年行业调研报告&#xff0c;83%的面试官会通过此问题评估候选人的沟通能力与职业成熟度。 一、测试岗位的离职应答核心原则 1. 技术…

作者头像 李华
网站建设 2026/5/13 4:11:12

CVE-2025-15052:code-projects学生信息系统中的跨站脚本漏洞威胁分析

CVE-2025-15052&#xff1a;code-projects学生信息系统中的跨站脚本漏洞 严重性&#xff1a;中 类型&#xff1a;漏洞 CVE编号&#xff1a;CVE-2025-15052 在code-projects学生信息系统1.0版本中发现了一个漏洞。此漏洞影响了文件 /profile.php 中未知的代码。对参数 firstna…

作者头像 李华