括号序列十二届蓝桥杯

本题思路

动态规划,记录第i个字符下左括号比右括号多了多少

其中如果遇到的是左括号,那么就相当于j+1,但是多左括号,整体方案数不会发生变化,所以原本j下的方案数,就是现在j+1的方案数

转移方程为:dp[i][j]=dp[i-1][j-1];

如果遇到的是右括号,那么就相当于多了一个右括号,那么我们就枚举在这个右括号前面加上j个左括号的情况,加上j个括号,就相当于之前的括号小于j括号的全部情况相加,因为如果有j个括号那么j-1个括号的方案也包含在里面,其中因为多了一个右括号,那么如果要比这个状态多j个右括号的话,那对于i-1的就要加到j+1,于是状态转移方程就是dp[i][j]=dp[i-1][j+1]+......+dp[i-1][0],但是如果这样时间复杂度就会超限,于是我们思考dp[i][j-1]=dp[i-1][j]+......dp[i-1][0]

于是转移方程为:dp[i][j]=dp[i][j-1]+dp[i-1][j+1];

其中我们本题分成要加上多少左括号,和加上多少右括号,其中这两种情况相互独立,所以可以直接相乘(关于为什么相互独立,因为我们插入多少左右括号的顺序是一定的,例:要加入两个左括号,一个右括号,那么结果只能是 “ ) ( ( ” 如果是 ( ( ),那么他们本身就已经形成对应,这样显然不满足最少加入)

然后本题不需要写两个方法处理,只需要求出一个后,对序列进行镜像反转即可。

然后本题最小主要体现在,最后返回值时我们从小到大,枚举遇到第一个方案不为0的方案返回,这时加入括号序列最少

下面上代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main括号匹配 {
	static char cc[];
	static int n;
	static int mod=1000000007;
	static long dp[][]=new long[5002][5002];
	public static void main(String[] args) throws IOException {
		BufferedReader x = new BufferedReader(new InputStreamReader(System.in));
		String s=x.readLine();
		cc=s.toCharArray();
		n=s.length();
		long p=mnpp();
		reverse(cc);//反转看添加左括号的情况
		for(int i=0;i<n;i++)//镜像反转
			if(cc[i]=='(')
				cc[i]=')';
			else
				cc[i]='(';
		for(int i=0;i<=n;i++)
		Arrays.fill(dp[i], 0);
		//System.out.println(p);
		System.out.println((p*mnpp())%mod);
		/*为何相乘其原因是因为左右括号添加是相互独立的不会互相影响*/
	}
	public static void reverse(char[] arr){
        for(int i = 0;i < n / 2;i++){
            char temp = arr[n -i - 1];
            arr[n -i - 1] = arr[i];
            arr[i] = temp;
        }
    }
	public static long mnpp() {//定义第i个字符,到第i个字符左括号比右括号多j个的总方案数
		dp[0][0]=1;
		for(int i=1;i<=n;i++) {
			if(cc[i-1]=='(')//多了一个左括号,对方案数无影响,那就等于原本多n个就等于现在多n+1个的方案数相同
				for(int j=1;j<=n;j++)
					dp[i][j]=dp[i-1][j-1];
			else {//一旦多一个)就枚举左括号比右括号多n个的情况
				dp[i][0]=(dp[i-1][1]+dp[i-1][0])%mod;//对于0来说没有-1所以直接等于dp[i-1][j+1]+dp[i-1][j]
				for(int j=1;j<=n;j++)
				/*
				 * 如果左比右多j个就相当于从j+1到0的全部情况相加
				 * 相当于)括号前加上j个括号,加上因为这个时候多了一个)括号,
				所以如果在i位置想让左括号比右括号多j个的话那么就要有j+1个左括号
				所以要加到j+1,然后dp[i][j-1]=dp[i][j.....0],和dp[i][j]后面重合,所以可以用它代替
				*/
					dp[i][j]=(dp[i-1][j+1]+dp[i][j-1])%mod;
			}
		}
//		for(int i=0;i<=n;i++) {
//			for(int j=0;j<=n;j++)
//				System.out.print(dp[i][j]+" ");
//			System.out.println();
//		}
		for(int i=0;i<=n;i++)//从小到大去搜,第一个满足条件的就是最小的
		if(dp[n][i]!=0)
			return dp[n][i];
		return -1;
	}
}

这题真的感觉很难,我是真的不会,最后参考y总的视频思路大概总结出,还是太菜,呜呜呜

如有侵权联系删

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值