我已经能够把我的解决方案减少到固定的时间。是否有可能进一步将这一比率降低任何常数?(除了琐事,即插入常量,而不是延迟导入)。具体来说,如果有不使用日志的方法,我想加快fastMinPayout的速度。
可爱的幸运羔羊是一个追随者,并不是所有的苦差事。偶尔,当兰布达指挥官感到慷慨时,她会分发幸运羔羊(兰伯达的万能金钱雄鹿)。追随者可以用幸运的羊羔买第二双袜子,枕头作为他们的铺位,甚至第三天的饭!然而,实际上分发羊羔并不容易。每个追随者队伍都有一个严格的资历等级,这必须得到尊重--否则,这些追随者会反抗,你们都会再次被降职为奴才!为了避免叛乱,你必须遵守4条关键规则:
请注意,您可能无法分发所有的羔羊。一只羔羊不能再细分。也就是说,所有的追随者都必须得到一个正整数的羔羊数。编写一个名为“答案”( total_lambs )的函数,其中total_lambs是要除以的讲义中羊羔的整数。它应该返回一个整数,表示能够分享羊羔的最小和最大数目的区别(也就是说,尽可能慷慨地对待你付出的人和尽可能吝啬的人),同时仍然遵守上述所有规则以避免叛乱。例如,如果你有10只羔羊,并且尽可能慷慨的话,你只能支付3只追随者(1,2,4只羔羊,按等级排列),而如果你吝啬的话,你可以付给4名追随者(1,1,2和3只羔羊)。因此,答案(10 )应该返回4-3 =1以保持趣味性,Lambda指挥官改变了幸运羔羊支付的大小:您可以期望total_lambs总是在100亿到10亿之间( 10 ^ 9)。
''' Recursive form
Rules:
1) A0 = 1
2) An+1 !> 2*An
3) An-1 + An-2 !> An
4) n -> inf
Rewritten:
1) A0 = 1
2) An <= 2*An-1
3) An >= An-1 + An-2
4) n -> inf
Therefore:
A0 = 1, A-1 = 0, A-2 = 0
An-1 + An-2 <= An <= 2*An-1
'''
def maxPayout(LAMBs):
'''
Given An-1 + An-2 <= An <= 2*An-1
An is maximized when An = 2*An-1
'''
# payouts[0] and payouts[1] exist as 'dummy' payouts
payouts = [0, 0, 1]
LAMBs -= payouts[-1]
while (LAMBs >= 0):
payouts.append(2*payouts[-1])
LAMBs -= payouts[-1]
# -2 for first two 'dummy' payouts and -1 for extra payout
return len(payouts) - 2 - 1
def minPayout(LAMBs):
'''
Given An-1 + An-2 <= An <= 2*An-1
An is minimized when An = An-1 + An-2
'''
# payouts[0] and payouts[1] exist as 'dummy' payouts
payouts = [0, 0, 1]
LAMBs -= payouts[-1]
while (LAMBs >= 0):
payouts.append(payouts[-1] + payouts[-2])
LAMBs -= payouts[-1]
# -2 for first two 'dummy' payouts and -1 for extra payout
return len(payouts) - 2 - 1
def solution(total_lambs):
return minPayout(total_lambs) - maxPayout(total_lambs)
def fastMaxPayout(LAMBs):
'''
Since maxPayout follows An = 2*An-1, maxPayout follows
geometric sequence that can be reduced to exponential.
An = 2^n
Then we solve for sum(An = 2^n) <= LAMBs and the geometric
series' sum formula follows:
Sn = A0 * 1-r^n / (1-r)
Sn = 1 * 1-2^n / (1-2)
Sn = 2^n - 1
Now we finally solve (Sn = 2^n - 1) <= LAMBs
2^n <= LAMBs + 1
n <= log2(LAMBs + 1)
n = floor(log2(LAMBs + 1)) = (LAMBs + 1).bit_length() - 1
'''
return (LAMBs + 1).bit_length() - 1
def fastMinPayout(LAMBs):
'''
Since minPayout follows An = An-1 + An-2, minPayout follows
a shifted Fibonnacci sequence. Apply Binet's formula to
derive the nth Fibonnacci sequence.
An-1 = Fn = ((1+sqrt(5) / 2)^n - (1-sqrt(5) / 2)^n) / sqrt(5)
Substitute constants for variables to simplify
let a = 1+sqrt(5) / 2
let b = 1-sqrt(5) / 2
let x = An-1 * sqrt(5)
x = a^n - b^n
a^n = x + b^n
n = loga(x + b^n)ls
And since lim n->inf b^n = 0, Binet's formula approximates:
n = loga(x)
Now we finally solve (Sn = An+2 - 1) >= LAMBs
n+3 = loga(An+2 * sqrt(5)) = loga((An+2 - 1 + 1) * sqrt(5))
n = loga((LAMBs + 1) * sqrt(5)) - 3
'''
from math import log, ceil, sqrt
return int(ceil(log((LAMBs + 1 + 0.5)*sqrt(5), (1+sqrt(5)) / 2)) - 3)
def fastSolution(total_lambs):
return fastMinPayout(total_lambs) - fastMaxPayout(total_lambs)
print(solution(143), fastSolution(143))发布于 2019-05-02 01:53:13
除了琐事,比如插入常数
这是一个常量,但也许你会把它看作是非平凡的。首先,它允许将一个除法转化为(更便宜的)乘法。
与其向math.log()提供两个args,不如使用这种更快的技术:
# one-time init
rad_five = sqrt(5)
phi = (1 + sqrt(5)) / 2
recip_phi = 1 / phi
# compute log base b, that is, base phi
log((LAMBs + 1 + 0.5) * rad_five) * recip_phi使用1 arg调用,然后再乘以肯定会跑得更快。
我们接受最多10亿的数字,然后计算大量详细的尾数位,结果ceil()丢弃了其中的大部分。也就是说,您真正关心的唯一输入值是那些将日志结果超过下一个整数格点的值。将这些值存储在有序查找表中。phi重复乘法会帮助你找到它们。
在运行时,使用查找表上的二进制搜索计算相关的日志结果。
是的,你是对的,你想把imports提升到最顶尖的位置.
发布于 2019-05-02 08:16:58
snake_case。你的评论很清楚,它们解释了为什么要做一些事情。
payouts list这份清单是不必要的。您只使用它的最后一个元素及其长度。更好的做法是只使用变量,就像标准的斐波纳契生成器和itertools.count来跟踪支出的数量。
def max_payouts(lambs):
payout = 1
for i in count():
if lambs <= 0:
return i
payout *= 2
lambs -= payout
def min_payouts(lambs):
a, b = 0, 1
for i in count():
if lambs <= 0:
return i
a, b = b, a + b
lambs -= bhttps://codereview.stackexchange.com/questions/219515
复制相似问题