蓝桥杯 Java 括号序列

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

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

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

第三步:把两个方案相乘

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

第一步中做动态规划

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

fij = fi-10\~j的方案和

cnt1表示需要的总左括号数

f11\~cnt1方案都只有一个

f10如果不成立方案数为0否则为1

注意:

  1. 这个算法可以利用优化简化复杂度,具体相见代码
  2. fij对j有要求,j最小是当前右括号个数减去当前位置的左边的括号数(这个在遍历数组的时候利用前缀和求解),也就是所需的左括号的最小(如果为负最小值为0)。
  3. 注意要取余数,最后相乘之后也需要求余
java 复制代码
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];
  }
}
相关推荐
Anastasiozzzz1 分钟前
从有限状态机到智能体图:传统 FSM 与 Agent Graph的演进
java·人工智能·python·ai
小欣加油6 小时前
leetcode56 合并区间
c++·算法·leetcode·职场和发展
wang09076 小时前
自己动手写一个spring之IOC_2
java·后端·spring
来杯@Java7 小时前
学生选课管理系统(基于springboot+vue前后端分离的项目)计算机毕业设计java
java·spring boot·spring·vue·毕业设计·maven·mybatis
不知名的老吴8 小时前
线程的生命周期之线程“插队“
java·开发语言·python
ANnianStriver8 小时前
PetLumina-02-后端开发与前后端联调
java·ai·sa-token
杨了个杨89828 小时前
Keepalived + Nginx + HAProxy 高可用架构部署实战案例
java·nginx·架构
8Qi89 小时前
LeetCode 516:最长回文子序列
算法·leetcode·职场和发展·动态规划
马士兵教育10 小时前
Java还有前景吗?Java+AI大模型学习路线及项目?
java·人工智能·python·学习·机器学习