首页 > 试题广场 >

合法的括号序列

[编程题]合法的括号序列
  • 热度指数:374 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个仅包含'('、')'和'?'三种字符构成的字符串,'?'字符可以代替左括号或者右括号。请问该字符串可以代表多少种不同的合法括号序列?

提示:建议python考生使用pypy提交代码!

输入描述:
一个仅包含'('、')'和'?'的字符串,长度不超过2000。


输出描述:
合法序列的数量。由于数量可能过大,请对取模。
示例1

输入

????(?

输出

2

说明

共有2种不同的合法括号序列,"()()()"或"(())()"。

备注:
 

解法

假设字符串长度为 n,可以考虑使用动态规划求解。令 dp[i][j] 表示前 i 个字符中,左括号比右括号多 j 个的方案数。考虑第 i+1 个字符:

  1. 如果是左括号,则 dp[i+1][j+1] = dp[i][j]。

  2. 如果是右括号,则 dp[i+1][j-1] = dp[i][j]。

  3. 如果是问号,则既可以代表左括号,也可以代表右括号,因此 dp[i+1][j+1] = dp[i][j] + dp[i+1][j-1]。

最终答案即为 dp[n][0],表示左右括号数量相等的方案数。

需要注意的是,由于原始字符串中可能存在 ? 字符,因此需要初始化 dp[0][0] = 1,并将剩余的 dp[0][j] 和 dp[i][j] 的值都设为 0。

def count_valid_parentheses(s: str) -> int:
    n = len(s)
    dp = [[0] * (n + 1) for _ in range(n + 1)]
    dp[0][0] = 1

    for i in range(1, n + 1):
        if s[i - 1] == "(":
            for j in range(i):
                dp[i][j + 1] += dp[i - 1][j]
        elif s[i - 1] == ")":
            for j in range(i):
                if j > 0:
                    dp[i][j - 1] += dp[i - 1][j]
        else:  # s[i-1] == '?'
            for j in range(i):
                dp[i][j + 1] += dp[i - 1][j]
                if j > 0:
                    dp[i][j - 1] += dp[i - 1][j]

    return dp[n][0]
s  = input()
print(count_valid_parentheses(s)%(1000000007))
发表于 2023-03-21 13:28:49 回复(1)
import java.util.Scanner;
import java.util.*;

public class Main {
    static int mod = (int) (Math.pow(10, 9) + 7);
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        char[] input = in.nextLine().toCharArray();
        if (input[0] == ')') {
            System.out.println(0);
            return;
        }
        int len = input.length;
        int[][] dp = new int[len][len];
        dp[0][1] = 1;
        for (int i = 0; i < len - 1; i++) {
            if (input[i + 1] == ')' || input[i + 1] == '?') {
                for (int j = 1; j < len; j++) {
                    dp[i + 1][j - 1] += dp[i][j];
                    dp[i + 1][j - 1] %= mod;
                }
            }
            if (input[i + 1] == '(' || input[i + 1] == '?') {
                for (int j = 0; j < len - 1; j++) {
                    dp[i + 1][j + 1] += dp[i][j];
                    dp[i + 1][j + 1] %= mod;
                }
            }
        }
        System.out.println(dp[len - 1][0]);
    }

}
设dp[i][j]表示第i个字符,还剩下j个左括号的方案数
若第i+1个字符是左括号,则dp[i+1][j+1]+=dp[i][j]
若第i+1个字符是右括号,则dp[i+1][j-1]+=dp[i][j]
若第i+1个字符是问号,则dp[i+1][j+1]+=dp[i][j],dp[i+1][j-1]+=dp[i][j]
答案为:dp[n][0]

编辑于 2023-03-16 17:20:48 回复(0)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2010;
const int mod=1e9+7;

int main() {
    string s; cin>>s;
    int n=s.length();
    // 表示到i时有j个待匹配的右括号
    vector<vector<ll>>f(n+10, vector<ll>(n+10, 0));
    if(s[0]=='('||s[0]=='?') f[0][1]=1;
    for(int i=1; i<n; i++){
        if(s[i]=='('||s[i]=='?'){
            for(int j=1; j<n; j++){
                f[i][j]+=f[i-1][j-1];
                f[i][j]%=mod;
            }
        }
        if(s[i]==')'||s[i]=='?'){
            for(int j=0; j<n-1; j++){
                f[i][j]+=f[i-1][j+1];
                f[i][j]%=mod;
            }
        }
    }
    cout<<f[n-1][0]<<endl;
}
// 64 位输出请用 printf("%lld")
发表于 2023-03-14 20:54:02 回复(0)

记忆化搜索

dfs(i,j)代表前i个字符,左括号比右括号多j个的方案数

import sys
from functools import cache

sys.setrecursionlimit(10000)
def vaildNum(s: str):
    n = len(s)

    @cache
    def dfs(i: int, j: int) -> int:
        if j < 0:
            return 0
        if i == 0:
            return 1 if j == 0 else 0
        if s[i - 1] == "(":
            return dfs(i - 1, j - 1) % MOD
        elif s[i - 1] == ")":
            return dfs(i - 1, j + 1) % MOD
        else:
            return (dfs(i - 1, j - 1) + dfs(i - 1, j + 1)) % MOD

    return dfs(n, 0)


s = input().strip()
MOD = 10 ** 9 + 7
print(vaildNum(s))
发表于 2023-09-01 19:12:55 回复(0)
s = input()
n = len(s)
if s[0] == ')':
    print(0)
else:
    dp = [[0 for _ in range(n)] for _ in range(n)]
    dp[0][1] = 1
    for i in range(1, n):
        if s[i] == '(' or s[i] == '?':
            for j in range(1, n):
                if j > i+1 or j > n-i-1:
                    break
                dp[i][j] += dp[i-1][j-1]
                dp[i][j] %= (1e9+7)
        if s[i] == ')' or s[i] == '?':
            for j in range(0,n-1):
                if j > i+1 or j > n-i-1:
                    break
                dp[i][j] += dp[i-1][j+1]
                dp[i][j] %= (1e9+7)
       

    print(int(dp[n-1][0]))

发表于 2023-03-14 22:04:36 回复(0)

问题信息

难度:
5条回答 3040浏览

热门推荐

通过挑战的用户

合法的括号序列