• 蓝桥杯 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. 注意要取余数,最后相乘之后也需要求余
    1. import java.util.Scanner;
    2. // 1:无需package
    3. // 2: 类名必须Main, 不可修改
    4. // 先算一次只加左括号的方案
    5. // 再算只加右括号的方案(镜像对称即可)
    6. // 两方案相乘
    7. public class Main{
    8. static long M = 1000000007;
    9. static char[] cs;
    10. public static void main(String[] args){
    11. Scanner sc = new Scanner(System.in);
    12. cs = sc.nextLine().toCharArray();
    13. long ans = clac();
    14. int n = cs.length;
    15. for(int i = 0,j = n-1;i < j;i++,j--){
    16. char temp = cs[i];
    17. cs[i] = cs[j];
    18. cs[j] = temp;
    19. }
    20. for(int i = 0;i < n;i++){
    21. if(cs[i] == '(')cs[i] = ')';
    22. else cs[i] = '(';
    23. }
    24. ans *= clac();// 反转后再来一遍
    25. System.out.println(ans%M);
    26. }
    27. public static long clac(){
    28. int[] sum = new int[5001];
    29. int cnt1 = 0;
    30. int cnt2 = 0;
    31. int n = 0;
    32. long[][] f = new long[5001][5001];// 遍历第i个,添加j个左括号的结果
    33. int ri = 1;
    34. for(char c:cs){
    35. if(c == '('){
    36. sum[ri]++;
    37. cnt2++;
    38. }else{
    39. ri++;
    40. n++;
    41. if(cnt2 == 0){
    42. cnt1++;
    43. }else{
    44. cnt2--;
    45. }
    46. }
    47. }
    48. for(int i = 1;i <= n;i++){// SUM转为前缀和
    49. sum[i] += sum[i-1];
    50. }
    51. for(int j = 0;j <= cnt1;j++){
    52. f[1][j] = 1;
    53. }
    54. if(sum[1] == 0){// 如果第一个右括号前没有左括号,不加括号的方案无效
    55. f[1][0] = 0;
    56. }
    57. // for(int i = 2;i <= n; i++){// 遍历右括号
    58. // for(int j = Math.max(0,i-sum[i]);j <= cnt1;j++){// 加多少左括号,注意有下限
    59. // for(int k = 0;k <= j;k++){
    60. // f[i][j] = (f[i][j] + f[i-1][k])%M;
    61. // }
    62. // }
    63. // }
    64. // 优化上文的算法
    65. for(int i = 2;i <= n; i++){// 遍历右括号
    66. long[] ne = new long[cnt1+1];
    67. ne[0] = f[i-1][0];
    68. for(int k = 1;k <= cnt1;k++){
    69. ne[k] = ne[k-1] + f[i-1][k];
    70. ne[k] %= M;
    71. }
    72. for(int j = Math.max(0,i-sum[i]);j <= cnt1;j++){// 加多少左括号,注意有下限
    73. f[i][j] += ne[j];
    74. }
    75. }
    76. return f[n][cnt1];
    77. }
    78. }

  • 相关阅读:
    【FPGA教程案例11】基于vivado核的除法器设计与实现
    docker 配置 Mysql主从集群
    【优选算法精品】前缀和
    CDN加速解密
    NOIP2023模拟1联测22 黑暗料理
    python的for循环语句的用法及实例
    使用pdfplumber提取pdf中的文字
    前端面试宝典React篇20 React 中你常用的工具库有哪些?
    C++基础入门 --- 【学习指南】
    Mysql的事务以及存储引擎
  • 原文地址:https://blog.csdn.net/weixin_45322373/article/details/134055223