算法 – 动态规划:计算第k个括号序列

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 <106).我无法为此制定一个子问题.我试图通过使用加泰罗尼亚的号码来解决这个问题,但似乎没有取得任何成功.我不想看到解决方案,因为它无助于学习.请帮助我找出一个子问题.

最佳答案 设N表示序列的长度(即2 n).

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

如果你有一个函数,countValid(N,深度)你可以解决原来的问题如下:

>如果深度< 0这是不可能的(负深度意味着无效序列)
>如果k < countValid(N-1,深度1)追加((因为所搜索的序列位于剩余搜索空间的前半部分)
>否则追加)(因为所寻求的序列位于整个搜索空间的后半部分)
>如果您选择(上方或​​上面的深度为1,如果您选择),则从1更新N-1和深度1继续.

countValid(N,depth)可以使用标准DP矩阵M进行动态编程来实现,其中两个参数作为索引:

>基本情况,M [0,0] = 1,因为有一个有效的0长度序列(空序列)
>对于第一列中的所有其他值,M [0,1 … N]为0.
>对于M [N,深度],你只需加起来

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

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

点赞