Python 基于ID列表高效计算XOR(^)校验和的方法
当我在谷歌上搜索关于Python列表理解的信息时,有人向我提供了一个谷歌foobar挑战,在过去几天里,我一直在慢慢地寻找乐趣。最新挑战: 有效地调用生成ID列表,忽略每一行中不断增加的ID数,直到剩下一个ID为止。然后,您应该对ID进行异或(^)以生成校验和。我创建了一个输出正确答案的工作程序,但是它的效率不足以在分配的时间内通过所有测试用例(通过6/10)。50000的长度应该在20秒内产生结果,但需要320秒 有人能把我引向正确的方向吗,但是请不要为我做这件事,我很高兴在这个挑战中激励自己。也许有一个数据结构或算法我可以实现,以加快计算时间 代码背后的逻辑:Python 基于ID列表高效计算XOR(^)校验和的方法,python,checksum,xor,Python,Checksum,Xor,当我在谷歌上搜索关于Python列表理解的信息时,有人向我提供了一个谷歌foobar挑战,在过去几天里,我一直在慢慢地寻找乐趣。最新挑战: 有效地调用生成ID列表,忽略每一行中不断增加的ID数,直到剩下一个ID为止。然后,您应该对ID进行异或(^)以生成校验和。我创建了一个输出正确答案的工作程序,但是它的效率不足以在分配的时间内通过所有测试用例(通过6/10)。50000的长度应该在20秒内产生结果,但需要320秒 有人能把我引向正确的方向吗,但是请不要为我做这件事,我很高兴在这个挑战中激励自
无论是
templast
还是answerlist
都不是真正需要的。让我们在你的代码中进行几次测试,看看如何消除它们。< /P>
templast
的初始化设置为一行程序。这:
templist = []
for y in range (x,x + length):
templist.append(y)
变成这样:
templist = list(range(x, x + length))
answerlist.extend(templist[:lengthmodified])
应答列表
执行相同的操作。这:
for d in range (0,lengthmodified):
answerlist.append(templist[d])
变成这样:
templist = list(range(x, x + length))
answerlist.extend(templist[:lengthmodified])
lengthmodified-=1
和x+=length
,我们有:
templist = list(range(x, x + length))
answerlist.extend(templist[:lengthmodified])
for n in answerlist:
prestringresult ^= n
answerlist = []
与其扩展answerlist
,迭代它,然后清除它,不如只迭代templast
templist = list(range(x, x + length))
for n in templist[:lengthmodified]:
prestringresult ^= n
现在也不需要圣殿骑士,所以让我们也跳过构建它
for n in range(x, x + lengthmodified):
prestringresult ^= n
templast
和answerlist
不见了
这里唯一缺少的部分是工作answerlist.append(int(stringresult))
返回。我会留给你去弄清楚的
总的来说,这里的教训是尽可能避免显式的for
循环。为遍历容器的
循环编写大量的,这是一种C思维方式。在Python中,通常有多种方法可以一次彻底检查集合。这样做可以利用该语言快速的内置操作
另外,惯用Python也很容易阅读。您可能需要一种不同的方法,而不仅仅是像John那样的小改进。我刚刚写了一个解决方案,可以在我的电脑上在大约2秒钟内完成回答(0,50000)
。我仍然一行一行地做,但不是对行范围内的所有数字进行XOR运算,而是一点一点地做。行中设置了多少个1位数字?[*]奇数数字?然后我翻转我答案的1位。对于2位、4位、8位等,直到230位,也是如此。因此,对于每一行,它只是31个小计算(而不是实际上对数万个数字进行XOR运算)
[*]可以在恒定时间内快速计算,仅从范围的开始/停止
编辑:既然您要求提供另一个提示,下面介绍如何计算在某个范围(a、b)内设置1位的频率。计算它设置在范围(0,a)内的频率,并从设置在范围(0,b)内的频率中减去该频率。如果范围从零开始,则更容易。在某个范围(0,c)内,1位设置的频率是多少?简单:c//2次。那么,在某个范围(a,b)中,1位设置的频率是多少?只需b//2-a//2次。较高的位是相似的,只是稍微复杂一点
编辑2:哦,等等,我刚想起来。。。有一种简单的方法可以计算某个范围(a,b)内所有数字的异或。再次将工作划分为工作范围(0,a)和范围(0,b)。某些范围(0,c)内的所有数字的异或很容易,因为有一个很好的模式(如果对从0到30的所有c进行异或,您将看到它)。使用这个,我现在在大约0.04秒的时间内解出答案(0,50000)
,,,我在不使用列表的情况下得到了一点改进,但它仍然会在大数目的情况下失败。嵌套循环会降低速度。我认为你需要遵循波希曼的逻辑,因为暴力很少是解决这类问题的方法
在这个问题上,大多数人都会被超过时间限制。是的!
这个问题可以这样得出结论:“在恒定时间内,找出位于一定范围内的所有数字的异或。”是的,恒定时间
所以从3-6开始,答案应该是O(1)时间内的3^4^5^6=4
解决方案:
XOR在本质上是关联的。所以A^B^C可以写成B^A^C。
此外,我们知道XOR的意思是:“AND”将相同的位转换为True,即1,将不同的位转换为2
根据这两种性质,我们可以写:
3-6中所有数字之间的异或可以写成:
3^4^5^6 = (0^1^2)^(0^1^2) ^ (3^4^5^6)
= (0^1^2^3^4^5^6) ^ (0^1^2) (this comes from the associative nature of xor)
= XOR betn all the numbers from (0-6) ^ XOR betn all the numbers from (0-2)...eq(1)
现在,如果我们能在一个恒定的时间内找到从0到某个整数的所有数字的异或,我们就会得到答案
幸运的是,我们有一种模式:
请参见以下示例:
(0-1): 0 ^ 1 = 1 (1)
(0-2): 0 ^ 1 ^ 2 = 3 (2+1)
(0-3): 0 ^ 1 ^ 2 ^ 3 = 0 (0)
(0-4): 0 ^ 1 ^ 2 ^ 3 ^ 4 = 4 (4)
(0-5): 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 = 1 (1)
(0-6): 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 = 7 (6+1)
(0-7): 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 = 0 (0)
(0-8): 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ 8 = 8 (8)
So the pattern for finding the xor between all the integers between 0 to n is:
if n%4 == 1 then, answer = 1
if n%4 == 2 then, answer = n+1
if n%4 == 3 then, answer = 0
if n%4 == 0 then answer = n
Therefore, XOR(0-6) becomes 7 (since 6%4 ==2) and XOR(0-2) becomes 3 (since 2%4 ==2)
Therefore, the eq(1) now becomes:
3^4^5^6 = 7 ^ 3 = 4
现在问题很简单,我们大多数人都会因为超过时间限制的错误而陷入困境,因为我们试图在每个循环中进行异或运算,如果输入/迭代的数量增加,这将是巨大的。
下面是我用python编写的工作解决方案,所有测试用例都通过了google的测试:
#Main Program
def answer(start, length):
checkSum = 0
for l in range(length, 0, -1):
checkSum = checkSum ^ (getXor(start + l-1) ^ getXor(start-1))
start = start + length
return checkSum
def getXor(x):
result = [x, 1, x+1, 0]
return result[x % 4]
你有两个内环。试着摆脱它们。这能让它快多少?你是对的。我修剪了John提到的脂肪,在运行时大大减少了脂肪,但仍然不够好。您的解决方案听起来非常有趣,1.52运行时听起来很棒。但是,我不熟悉xoring“位”的过程