本题思路
动态规划,记录第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总的视频思路大概总结出,还是太菜,呜呜呜
如有侵权联系删