有人可以帮我解决这个问题吗?我会输入问题,然后给出一些我的想法/替代解决方案。
所以问题就在于,给出一个这样的括号:
[[]]
我们希望为每个括号分配一个组号(组1或组2)。一个有效的赋值意味着如果你只看第一组中的括号,它会形成一个有效的,平衡的括号字符串(这就像[] [[]]之类的东西,而不是像[] [] []那样的东西。同样的第二组是正确的。组不必是连续的。我们想要计算将这些括号分成两组的方法。
在[[]]上面的示例字符串上,答案是6,这里是枚举:(1 =组1,2 =组2)
[[]]
1.1111
2.2222
3.1221
4.2112
5.1212
6.2121
该安排不必包括所有组(如安排1.和2)。
思想
一个明显的暴力解决方案,最多可以使用32个括号,相当快速,是一个32位整数,表示哪个括号是单个组的一部分。或者我们可以使用数组。运行时间是O(2 ^ N)(我想),这太慢了?
通过查看问题,我认为您给出的原始括号字符串必须预先平衡,否则无法选择子集,使第1组和第2组达到平衡。
我还注意到你可以分开组件 - 字符串“[]”有2个排列,所以字符串“[] []”有4个排列。 (您可以在每个组件中找到方法的数量并将它们相乘)。
我对如何将这些想法纳入算法感到困惑。我写了蛮力程序,我检查了字符串“[]”,“[[]]”,“[[[]]]”和“[[[[]]]]”,我不是真的看一个模式。
从将这些字符串插入我的暴力程序后,我得到:
"[]" = 2
"[[]]" = 6
"[[]]" = 20
"[[[[]]]]" = 70
代码:
char buf[1000];
int N;
bool isValid(int mask)
{
int lv = 0;
for (int i = 0; i < N; i++)
{
if (mask & (1 << i))
{
if (buf[i] == '(')
{
lv++;
}
else
{
lv--;
}
if (lv<0)
{
return false;
}
}
}
return lv==0;
}
int main()
{
scanf("%s", buf);
N = strlen(buf);
int ways = 0;
for (int i = 0; i < (1 << N); i++)
{
if (isValid(i) && isValid(~i))
{
ways++;
}
}
printf("Number of ways is %d\n", ways);
return 0;
}
答案 0 :(得分:2)
如果有任何帮助,对于[[[[]]等“中心”字符串,您可以使用ways(1) = 2
和ways(n) = ways(n-1)*(4*n-2)/n
(或 C(2n,n)来计算您的使用方式)如果你愿意的话),其中n是嵌套的深度。
嵌套但不是“中心”的组(如[[] []])似乎遵循类似的模式,但我无法找出正确的公式。
修改强>
我们的符号功率耗尽,所以我将使用texify来表达数学公式。我想出了类似的东西:
周围的群组(您可以按this更改公式)。
答案 1 :(得分:2)
扩展ishi的答案,我认为可以在O(N ^ 2)中完成,因为d + e等于前缀的深度。下面的代码得到了相同的结果。
/*
How many ways are there to split a string
of brackets into two such that both are balanced.
*/
#include <iostream>
#include <string>
using namespace std;
#define MAXN 1000
#define M 1000000007
int N, dp[MAXN][MAXN];
string s;
int recurse(int k, int i, int p) {
if (i >= N) {
return k == 0 ? 1 : 0;
}
if (k < 0 || p-k < 0) {
return 0;
}
int &ans = dp[k][i];
if (ans != -1) {
return ans;
}
ans = 0;
if (s[i] == '[') {
ans += recurse(k+1,i+1,p+1)+recurse(k,i+1,p+1);
return ans;
}
if (s[i] == ']') {
ans += recurse(k-1,i+1,p-1)+recurse(k,i+1,p-1);
return ans;
}
return 0;
}
int main() {
cin >> s;
N = s.size();
for (int k = 0; k < N; k++) {
for (int i = 0; i < N; i++) {
dp[k][i] = -1;
}
}
cout << recurse(0,0,0) << endl;
}
答案 2 :(得分:1)
更容易理解的解决方案。
public int splitString(String s){
int gOneC=0;
int gTwoC=0;
Map<String, Integer> memo = new HashMap<>();
return splitStringRecur(s,0, gOneC, gTwoC, memo);
}
private int splitStringRecur(String s, int i, int gOneC, int gTwoC, Map<String, Integer> memo) {
if(i == s.length()){
if(gOneC==0 || gTwoC==0) return 1;
}
String t = i+"-"+gOneC+"-"+gTwoC+"";
if(memo.containsKey(t)) return memo.get(t);
int gc =0;
int gs =0;
if(s.charAt(i)=='('){
gc = splitStringRecur(s, i+1, gOneC+1, gTwoC,memo);
gs = splitStringRecur(s, i+1, gOneC, gTwoC+1,memo);
}else {
if(gOneC > 0){
gc += splitStringRecur(s, i+1, gOneC-1, gTwoC,memo);
}
if( gTwoC >0){
gs += splitStringRecur(s, i+1, gOneC, gTwoC-1,memo);
}
}
memo.put(t, gc+gs);
return gc+gs;
}