鉴于从1
到n
的一组连续数字,我试图找到不包含连续数字的子集数量。
例如,对于集合[1, 2, 3]
,一些可能的子集是[1, 2]
和[1, 3]
。前者不会计算,而后者则不计算,因为1和3不是连续的数字。
这就是我所拥有的:
def f(n)
consecutives = Array(1..n)
stop = (n / 2.0).round
(1..stop).flat_map { |x|
consecutives.combination(x).select { |combo|
consecutive = false
combo.each_cons(2) do |l, r|
consecutive = l.next == r
break if consecutive
end
combo.length == 1 || !consecutive
}
}.size
end
它有效,但我需要它在n <= 75
的12秒内更快地工作。如何优化此方法,以便我可以处理高n
值的汗水?
我看了看:
和其他一些人。我似乎无法找到答案。
建议重复是Count the total number of subsets that don't have consecutive elements,虽然这个问题略有不同,因为我在Ruby中要求这个优化,我不想在我的答案中使用空子集。如果我最初发现那个问题,这个问题会非常有用!但SergGr的答案正是我所寻找的。 p>
答案 0 :(得分:4)
虽然@ user3150716的想法是正确的,但细节是错误的。特别是你可以看到n = 3
有4个子集:[1]
,[2]
,[3]
,[1,3]
,而他的公式只给出3.这是因为他错过了子集[3]
(即仅由[i]
组成的子集),并且错误累积为较大的n
。此外,我认为如果您从1
开始而不是n
,则更容易思考。所以正确的公式将是
f(1) = 1
f(2) = 2
f(n) = f(n-1) + f(n-2) + 1
这些公式很容易使用恒定空间和O(n)
速度的简单循环进行编码:
def f(n)
return 1 if n == 1
return 2 if n == 2
# calculate
# f(n) = f(n-1) + f(n - 2) + 1
# using simple loop
v2 = 1
v1 = 2
i = 3
while i <= n do
i += 1
v1, v2 = v1 + v2 + 1, v1
end
v1
end
您可以在线查看此原始代码here
对于任何n <= 75
来说,这应该非常快。对于更大的n
,您可能需要一些额外的技巧,例如注意f(n)
实际上比Fibonacci number
f(n) = Fib(n+2) - 1
并且斐波纳契数的闭合公式理论上可以更快地计算出大n
。
答案 1 :(得分:1)
让{i ... n}没有连续数字的子集数为f(i),则f(i)为以下总和:
1)f(i + 1),这些子集中没有i的数量。
2)f(i + 2)+ 1,其中包含i的子集的数量(因此从子集中省略i + 1)
所以,
f(i)=f(i+1)+f(i+2)+1
f(n)=1
f(n-1)=2
f(1)将是你的答案。 您可以在O(logn)时间使用矩阵求幂(http://zobayer.blogspot.in/2010/11/matrix-exponentiation.html)来解决它。