我正在寻找一种合理快速的算法来计算OEIS序列A002845的术语。让我在这里重申它的定义。
设^表示取幂运算符。考虑具有n 2的形式2 ^ 2 ^ ... ^ 2的表达式,其中括号以所有可能的方式插入(可能的括号的数量由Catalan numbers给出)。这些表达式中的一些将具有相同的值,例如(2 ^ 2)^ 2 = 2 ^(2 ^ 2)。我们对给定n的不同值的数量感兴趣。
通过直接计算这些表达式有明显的暴力解决方案,但很明显,即使对于相对较小的n,所需的时间和空间也会迅速超过所有合理的限制。我对这个问题的多项式时间解决方案感兴趣。
答案 0 :(得分:3)
只需表示迭代基数2中的数字:Num
有x1,...,xp
类型的不同子Num
的(可能为空)列表,以便Num([x1,...,xp]) == 2^x1 + ... + 2^xp
。< / p>
这定义了一种写一个非负整数的独特方法;记得对指数进行排序,以便比较有意义。平等:
2^x + 2^x == 2^(x+1) == Num([x+1])
2^x + 2^y == Num([x,y])
时,x != y
(2^2^x)^2^y == 2^2^(x+y) == Num([Num([x+y])])
与加法的相关性/交换性一起允许你添加任意数字并为形式2 ^ 2 ^ k的数字计算x^y
;这类数字包含2(k = 0)并在^
下关闭,因此这保证了我们需要操作的每个数字都是这种形式。
此外,上面定义的等式永远不会增加树中的节点数,因此所有Num
的大小都为O(n)
。
所以时间复杂度实际上是O(C * n^k)
,它在C中是准线性的(C是第(n-1)个加泰罗尼亚数)。
答案 1 :(得分:1)
我认为这里最好的解决方案涉及动态编程,这是一个难以掌握的概念,但如果正确完成则非常有效。通过记住您已经完成的计算结果,然后使用这些知识将问题分解为更简单问题的子集,我们的想法是最小化您必须进行某个计算的次数。
例如,在你的2 ^(2 ^ 2)=(2 ^ 2)^ 2示例中,我们现在可以记住这两个等价于16的东西。所以现在当我们看到这个被加上到2 ^(2 ^(2 ^ 2))= 2 ^((2 ^ 2)^ 2)我们可以非常快速地将这些中的每一个识别为2 ^ 16,进行一次计算,我们现在有两个新的方程式添加到我们永远不必再次计算的值列表中。
然而,这可能似乎没有多大帮助,当你最终得到一系列带括号的问题,甚至更长的等价组时,它将为你节省大量的时间和复杂性。计算机要做很大的数字。下面的伪代码,我道歉,这是真正广泛的伪代码,这个问题相当粗糙,所以我不想写出整个算法。刚刚更详细地概述了这个概念
sortedEquivalencyVector; //Sorted greatest first, so we are more likely to se longest matches
function(expression)
if(portion of expression exists) //Remember, you can only do this from the end of the expression in toward the middle!
replace value at end of expression that matches with its already computed value
if(simplified version exists in vector) add original expression to vector
else compute value and add it to the vector
end
答案 2 :(得分:0)
比蛮力(但实际上仍然很昂贵)要好得多的一种方法是在第一个链接纸中使用“标准形式”的概念。给定n
,生成每个标准形式的度n
,对其进行评估,并将所有值保存在集合中。最后,检查集合的大小。
标准表格的语法是
S -> (2 ^ P)
P -> (S * P)
P -> S
S -> 2
您从S
开始,最后您应该有n
个终端(即2
s)。