蓝桥杯 Java 括号序列

本算法需要把问题分解成三步:

第一步:算出 ((() 填充 ( 的方案

第二步:算出 ((() 填充 ) 的方案

第三步:把两个方案相乘

第二步可以把原方案当成将 ((() 逆转成 ())) 再填充 ( ,这样就可以重复第一步用的算法

第一步中做动态规划

f[i][j]表示第i个右括号左边填充j个左括号的可用的方案数

f[i][j] = f[i-1][0~j]的方案和

cnt1表示需要的总左括号数

f[1][1~cnt1]方案都只有一个

f[1][0]如果不成立方案数为0否则为1

注意:

  1. 这个算法可以利用优化简化复杂度,具体相见代码
  2. f[i][j]对j有要求,j最小是当前右括号个数减去当前位置的左边的括号数(这个在遍历数组的时候利用前缀和求解),也就是所需的左括号的最小(如果为负最小值为0)。
  3. 注意要取余数,最后相乘之后也需要求余
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
// 先算一次只加左括号的方案
// 再算只加右括号的方案(镜像对称即可)
// 两方案相乘
public class Main{
  static long M = 1000000007;
  static char[] cs;
  
  public static void main(String[] args){
    Scanner sc = new Scanner(System.in);
    cs = sc.nextLine().toCharArray();
    long ans = clac();
    int n = cs.length;
    for(int i = 0,j = n-1;i < j;i++,j--){
      char temp = cs[i];
      cs[i] = cs[j];
      cs[j] = temp;
    }
    for(int i = 0;i < n;i++){
      if(cs[i] == '(')cs[i] = ')';
      else cs[i] = '(';
    }
    ans *= clac();// 反转后再来一遍
    System.out.println(ans%M);
  }

  public static long clac(){
    int[] sum = new int[5001];
    int cnt1 = 0;
    int cnt2 = 0;
    int n = 0;
    long[][] f = new long[5001][5001];// 遍历第i个,添加j个左括号的结果
    int ri = 1;
    for(char c:cs){
      if(c == '('){
        sum[ri]++;
        cnt2++;
      }else{
        ri++;
        n++;
        if(cnt2 == 0){
          cnt1++;
        }else{
          cnt2--;
        }
      }
    }
    for(int i = 1;i <= n;i++){// SUM转为前缀和
      sum[i] += sum[i-1];
    }
    for(int j = 0;j <= cnt1;j++){
      f[1][j] = 1;
    }
    if(sum[1] == 0){// 如果第一个右括号前没有左括号,不加括号的方案无效
      f[1][0] = 0;
    }
    // for(int i = 2;i <= n; i++){// 遍历右括号
    //   for(int j = Math.max(0,i-sum[i]);j <= cnt1;j++){// 加多少左括号,注意有下限
    //     for(int k = 0;k <= j;k++){
    //       f[i][j] = (f[i][j] + f[i-1][k])%M;
    //     }
    //   }
    // }
    // 优化上文的算法
    for(int i = 2;i <= n; i++){// 遍历右括号
      long[] ne = new long[cnt1+1];
      ne[0] = f[i-1][0];
      for(int k = 1;k <= cnt1;k++){
        ne[k] = ne[k-1] + f[i-1][k];
        ne[k] %= M;
      }
      for(int j = Math.max(0,i-sum[i]);j <= cnt1;j++){// 加多少左括号,注意有下限
        f[i][j] += ne[j];
      }
    }
    return f[n][cnt1];
  }
}

### 蓝桥杯括号序列问题的C++解法 对于蓝桥杯中的括号序列问题,有效的解决方案通常依赖于递归方法来生成所有可能的有效括号组合。这类问题的核心在于确保任何时候右括号的数量不超过左括号数量,并且当达到指定长度时正好用尽给定数目的一对括号。 在解决此类问题时,一种常见策略是从空字符串开始逐步构建合法的括号表达式。每当遇到未匹配的左括号时,则可以选择添加另一个左括号或者尝试闭合当前最近的一个未关闭的左括号。此过程通过递归来实现,直到形成完整的括号串为止[^1]。 下面展示了一个具体的C++代码片段用于生成特定数量`n`对应的全部有效括号排列方式: ```cpp class Solution { public: vector<string> generateParenthesis(int n) { vector<string> result; backtrack(result, "", 0, 0, n); return result; } private: void backtrack(vector<string>& res, string currentStr, int openCount, int closeCount, const int maxPairs){ // 如果已经形成了一个完整的括号对则加入结果集中 if(currentStr.length() == maxPairs * 2){ res.push_back(currentStr); return ; } // 尝试增加一个新的'('如果还有剩余配额 if(openCount < maxPairs) backtrack(res, currentStr+"(", openCount+1, closeCount,maxPairs); // 只要存在可被封闭的'(',就可以安全地加上')' if(closeCount<openCount ) backtrack(res,currentStr+")", openCount ,closeCount +1,maxPairs ); } }; ``` 上述算法利用了回溯技术,在每一步都尽可能多地探索不同的可能性路径,从而保证能够找到所有的可行方案而不遗漏任何一个潜在的结果集。这种方法不仅适用于LeetCode第22题这样的在线编程挑战平台上的题目,同样也适合处理其他类似的括号匹配场景下的实际应用案例[^2]。 #### 关键点总结: - 使用递归函数遍历所有可能的状态空间。 - 维护两个计数器分别记录已使用的左右括号数目。 - 当前状态满足条件即为所求之一;否则继续向下一层级深入搜索直至边界情况发生。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值