动态编程:计算第k个括号序列

时间:2014-10-18 07:07:25

标签: algorithm dynamic-programming catalan

n括号序列由n“(”s和n“)”s组成。

有效的括号序列定义如下:

你可以找到一种方法来重复擦除相邻的括号“()”直到它变空。

例如,“(())”是一个有效的括号,你可以删除第2和第3位置的对,它变为“()”,然后你可以将它变为空。 “)()(”不是有效的括号,在第2和第3位置上擦除它后,它变为“)(”你不能再删除。

现在,我们拥有所有有效的n个括号序列。按字典顺序查找第k个最小序列。

例如,以下是按字典顺序排列的所有有效3个括号序列:

((()))
(()())
(())()
()(())
()()()

来源:https://code.google.com/codejam/contest/4214486/dashboard#s=p3

注意:现在比赛和解决方案可供下载。

我通过使用C ++ STL中提供的next_permutation()来解决小输入(k <10 6 )。我无法为此制定一个子问题。我试图通过使用加泰罗尼亚的号码来解决这个问题,但似乎没有取得任何成功。我不想看到解决方案,因为它无助于学习。请帮助我找出一个子问题。

2 个答案:

答案 0 :(得分:2)

N 表示序列的长度(即2 n )。

关键是能够计算长度 N 的有效序列数。

如果您有一个函数 countValid N depth ),您可以按如下方式解决原始问题:

  1. 如果深度&lt; 0它是不可能的(负深度意味着无效序列)

  2. 如果 k &lt; countValid N -1,深度 +1)追加((因为所寻求的序列位于剩余的前半部分搜索空间)

  3. 否则追加)(因为所搜索的序列位于整个搜索空间的后半部分)

  4. 如果您选择上面的(深度,则从1更新 N -1和深度 +1如果您选择上面的),则为-1。


  5. countValid N depth )可以使用标准DP矩阵动态编程实现, M ,将两个参数作为索引:

    • 基本情况, M [0,0] = 1,因为一个有效的0长度序列(空序列)

    • 对于第一列中的所有其他值 M [0,1 ... N ]为0。

    • 对于 M [ N 深度],您只需加起来

      • 打开后有效序列的数量: M [ N -1,深度 -1]和
      • 关闭后有效序列的数量: M [ N -1,深度 +1]

      即: M [ N 深度] = M [ N -1,深度 -1] + M [ N -1,深度 +1]

答案 1 :(得分:0)

I know this is an old thread but some people may come back to this. I had a hard time implementing aioobe's solution, as I think it misses a step:

3.1) If you chose ")", then k = k - countValid(N-1, depth+1)

Intuitively the reasoning goes like this. If you selected to decrease the depth, then the sequence you are looking for is in the second part of the search space that is divided at (N, depth). If we keep k the same, it will at some point along the path be bigger than all the remaining number of solutions and our traversal doesn't work anymore. We need to subtract the number of solutions we excluded along the way for the traversal of the matrix to produce the desired results.

Here is some java code for finding the k-th element if you have the matrix D containing the number of valid sequences for each (N,depth):

// get k-th element
int N = 2*n;
int d = 0;
String str = new String("");
while (N>0 && d >= 0) {
  // invalid elements (out of bounds or 0)
  if (d+1 > n || D[N-1][d+1] == 0) {
    str += ")"; d--;
  } else if (d-1 < 0 || D[N-1][d-1] == 0) {
    str += "("; d++;
  } else {
    if (k <= D[N-1][d+1]) {
      // first part of search-space
      str += "("; d++;
    } else {
      // second part of search-space
      str += ")";
      k -= D[N-1][d+1]; // substract number of excluded solutions
      d--;
    }
  }
  N--;
}

// For valid strings k should be 1
if (k != 1) str = "Doesn't Exist!";