最长正则括号序列算法详解

ops/2024/12/27 1:29:01/

一、引言

在计算机科学中,处理括号序列的问题是一个常见且有趣的领域。本文将深入探讨如何寻找最长正则括号序列这一问题,包括问题的详细描述、解决该问题的算法思路、代码实现以及通过示例对算法进行深入剖析。

二、问题详细描述

(一)正则括号序列的定义

一个括号序列被认定为正则的,当且仅当通过合理地插入 “+” 和 “×” 操作符能够形成一个正确的数学表达式。例如:

  • “(())()” 是正则的,因为可以写成类似 “( ( ) ) × ( )” 这样的数学表达式。
  • “()” 本身就是一个简单的正则括号序列。
  • “(((())))” 也是正则的,能够形成有效的数学表达式。
    然而,像 “(”(左括号单独出现)、“())”(右括号多于左括号且不匹配)和 “((())(”(括号匹配不完整)这些都不是正则括号序列。

(二)输入与输出要求

  1. 输入
    • 输入为一个非空字符串,该字符串仅由 “(” 和 “)” 字符组成,并且字符串长度不超过 10⁶。例如:“)((())())((()))” 或者 “))((” 等都是可能的输入形式。
  2. 输出
    • 需要输出两个值:一是最长正则括号子序列的长度;二是这种最长正则括号子序列的数量。如果不存在正则括号子序列,则按照要求输出 “0 1”。

三、算法思路与实现

(一)核心算法函数longest_regular_bracket_sequence

  1. 数据结构初始化
    • 首先,我们使用一个栈stack来辅助记录左括号的位置。栈在处理括号匹配问题中是非常有效的数据结构
    • 同时,创建一个列表dp,其长度与输入字符串s相同,并且初始化为 0。dp列表的作用是存储以每个字符位置结尾的最长正则括号子序列的长度。
    • 代码如下:
    stack = []
    dp = [0] * len(s)
    
  2. 遍历字符串进行括号匹配与长度计算
    • 然后,对输入字符串s进行逐字符遍历:
    for i in range(len(s)):
    
     
    • 当遇到左括号 “(” 时:
      • 将当前左括号的索引位置i压入栈stack中。因为这个左括号可能在后续会与右括号匹配,通过栈可以方便地找到对应的左括号。
      • 代码为:if s[i] == '(': stack.append(i)
    • 当遇到右括号 “)” 时:
      • 首先要检查栈是否为空。如果栈为空,说明当前右括号没有与之匹配的左括号,这种情况下无法形成正则括号子序列(以当前位置结尾),所以不进行任何操作。
      • 如果栈不为空,说明找到了一对匹配的括号。此时,弹出栈顶元素,这个栈顶元素就是与当前右括号匹配的左括号的索引,记为matching_index
      • 接着,计算以当前右括号结尾的最长正则括号子序列的长度。其计算公式为dp[i] = dp[matching_index - 1] + i - matching_index + 1。这里的dp[matching_index - 1]表示匹配左括号前一个位置的最长正则括号子序列长度,i - matching_index + 1是当前匹配括号对本身的长度。通过将这两部分相加,就得到了以当前右括号结尾的最长正则括号子序列长度。
      • 代码为:
      elif s[i] == ')' and stack:matching_index = stack.pop()dp[i] = dp[matching_index - 1] + i - matching_index + 1
      
  3. 计算最终结果
    • 在遍历完整个字符串后,我们需要从dp列表中找出最大值,这个最大值就是最长正则括号子序列的长度max_length,通过max(dp)即可获取。
    • 接下来,计算最长长度出现的次数。如果max_length大于 0,那么通过dp.count(max_length)来统计;如果max_length等于 0,说明不存在正则括号子序列,按照要求数量为 1。
    • 代码如下:
    max_length = max(dp)
    count = dp.count(max_length) if max_length > 0 else 1
    return max_length, count
    

(二)输入读取、问题解决与输出部分

  1. 输入读取
    • 使用input().strip()简单地读取输入的字符串s,这里的strip()方法用于去除字符串可能存在的首尾空白字符。
  2. 问题解决与输出
    • 调用longest_regular_bracket_sequence函数,传入读取到的字符串s,得到最长正则括号子序列的长度length和数量count
    length, count = longest_regular_bracket_sequence(s)
    
     
    • 最后,按照要求输出结果:
    print(length, count)
    

四、示例深度剖析

(一)示例一

  1. 输入)((())())((()))
    • 算法开始执行时:
      • 初始化stack为空栈,dp为长度与输入字符串相同的全 0 列表。
      • 开始遍历字符串:
        • 第一个字符是 “)”,此时栈为空,不进行操作,dp[0]保持为 0。
        • 第二个字符是 “(”,将索引 1 压入栈,stack = [1]
        • 第三个字符是 “(”,将索引 2 压入栈,stack = [1, 2]
        • 第四个字符是 “)”,栈不为空,弹出栈顶元素 2,计算dp[3] = dp[2 - 1] + 3 - 2 + 1 = 0 + 2 = 2(这里dp[1]为 0)。
        • 第五个字符是 “)”,栈不为空,弹出栈顶元素 1,计算dp[4] = dp[1 - 1] + 4 - 1 + 1 = 0 + 4 = 4(这里dp[0]为 0)。
        • 以此类推,继续遍历和计算。
    • 最终计算得到dp列表的值(假设从 0 开始索引):[0, 0, 0, 2, 4, 0, 4, 6, 0, 2, 4, 6]
    • dp中找到最大值max_length = 6dp中值为 6 的元素有 2 个,所以count = 2
    • 输出为6 2

(二)示例二

  1. 输入))((
    • 初始化stackdp后开始遍历:
      • 第一个字符是 “)”,栈为空,不操作,dp[0]为 0。
      • 第二个字符是 “)”,栈为空,不操作,dp[1]为 0。
      • 第三个字符是 “(”,将索引 2 压入栈,stack = [2]
      • 第四个字符是 “(”,将索引 3 压入栈,stack = [2, 3]
    • 最终dp列表的值为[0, 0, 0, 0]
    • 最大值max_length = 0,按照规则count = 1
    • 输出为0 1

五、总结

通过上述对最长正则括号序列问题的详细描述、算法思路分析、代码实现以及示例剖析,我们能够全面地理解如何解决这类问题。在实际的算法设计和编程中,类似这种基于栈和动态规划思想(这里dp列表的使用体现了一定的动态规划思想)来处理字符串序列问题是非常常见的,希望本文能够帮助读者更好地掌握此类算法技巧。

希望这篇更加详细的文章能满足你的需求!


http://www.ppmy.cn/ops/145260.html

相关文章

【人工智能】用Python实现情感分析:从简单词典到深度学习方法的演进

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 情感分析是自然语言处理(NLP)中的一个重要任务,其目的是通过分析文本内容,识别出其中的情感极性,如正面、负面或中性。随着技术的不断…

GESP2024年12月认证C++五级( 第三部分编程题(2))

参考程序&#xff1a; #include<bits/stdc.h> using namespace std; #define ll long long int n, m; int cnt[1010]; vector<int> cs[1010]; ll calc(int aim) {int cur_cnt cnt[1];ll res 0;vector<int> tmp;for (int i 2; i<n; i){int buy max((…

虚拟局域网VLAN

✍作者&#xff1a;柒烨带你飞 &#x1f4aa;格言&#xff1a;生活的情况越艰难&#xff0c;我越感到自己更坚强&#xff1b;我这个人走得很慢&#xff0c;但我从不后退。 &#x1f4dc;系列专栏&#xff1a;网路安全入门系列 目录 一&#xff0c;VLAN二&#xff0c;静态VLAN配…

【网络安全】Web安全基础- 第一节:web前置基础知识

目录 前言一、 中间件 1.1消息中间件1.2数据库中间件1.3web服务器中间件1.4应用服务器中间件1.5远程过程调用中间件 二、源码 **组成部分&#xff1a;** 1、**前端&#xff08;客户端&#xff09;代码&#xff1a;**2、**后端&#xff08;服务器端&#xff09;代码**&#xff…

Redis 集群架构:高可用与扩展性

一、引言 在当今数字化时代&#xff0c;数据量呈爆炸式增长&#xff0c;对数据存储和处理的要求也越来越高。Redis作为一款高性能的键值对存储数据库&#xff0c;其集群架构在应对高并发、大数据量场景时展现出了独特的优势&#xff0c;成为众多企业构建高效、稳定系统的关键技…

CUDA11.4版本的Pytorch下载

由于CUDA11.4版本找不到对应的pip下载&#xff0c;可以用CUDA11.3版本 解决方案&#xff1a; 可以在对应环境输入&#xff1a; pip install torch1.11.0cu113 torchvision0.12.0cu113 torchaudio0.11.0 --extra-index-url https://download.pytorch.org/whl/cu113

Day53 图论part04

110.字符串接龙 经过上面的练习,大家可能会感觉 广搜不过如此,都刷出自信了,本题让大家初步感受一下,广搜难不在广搜本身,而是如何应用广搜。 代码随想录 import java.util.*;public class Main{public static void main (String[] args) {Scanner scanner = new Scanner…

日本IT行业|分享实用的开发语言及框架

在日本IT行业中&#xff0c;开发语言与框架的选择非常多样化&#xff0c;但也有一些特定的技术和框架更为流行。以下是对日本IT行业在用的开发语言与框架的详细分享&#xff1a; 开发语言 Java&#xff1a;Java在日本是一门非常稳定且受欢迎的编程语言&#xff0c;很多日本公…