为什么此代码在Hackerrank上显示“ 由于超时而终止”?
我正尝试在 Hackerrank 上的“ 30天代码”中的第29天:按位与中执行任务。这是任务:
任务
设置为 S = {1,2,3,... N }。从集合 S 中找到两个整数 A 和 B (其中 A < B ) strong>,使得 A和B 的值是最大可能值,并且还小于给定的整数 K 。在这种情况下,&表示按位AND运算符。
输入格式
第一行包含一个整数 T ,即测试用例的数量。每条 T 后续行均将测试用例定义为 2 空格分隔的整数,分别为 N 和 K 。
约束
1 <= T <= 10 ^ 3
2 <= N <= 10 ^ 3
2 <= K <= N输出格式
对于每个测试用例,在新行上打印 A和B 的最大可能值。
样本输入
3
5 2
8 5
2 2
示例输出
1
4
0
说明
N = 5, K = 2, S = {1,2,3 ,4,5}
和的所有可能值为:
1 。 A = 1, B = 2; A和B = 0
2 。 A = 1, B = 3; A和B = 1
3 。 A = 1, B = 4; A和B = 0
4 。 A = 1, B = 5; A和B = 1
5 。 A = 2, B = 3; A和B = 2
6 。 A = 2, B = 4; A和B = 0
7 。 A = 2, B = 5; A和B = 0
8 。 A = 3, B = 4; A和B = 0
9 。 A = 3, B = 5; A和B = 1
10 。 A = 4, B = 5; A和B = 4A&B 的最大可能值也是<( K = 2),所以我们在新行上打印1。
这是我的代码:
import math
import os
import random
import re
import sys
if __name__ == '__main__':
t = int(sys.stdin.readline())
for t_itr in range(t):
nk = sys.stdin.readline().split()
n = int(nk[0])
k = int(nk[1])
lst1 = [(a, b) for a in range(1, n + 1) for b in range(a + 1, n + 1)]
lst2 = [ a & b for (a,b) in lst1 if a & b < k]
print(max(lst2))
此任务共有6个测试用例,在测试用例1和2中,我的代码为True,但在接下来的4个测试用例中,它引发:'由于超时终止。
您能为我解释我错了吗?我该怎么做才能完成所有测试用例?感谢您的帮助!
答案 0 :(得分:2)
使得(某物)小于K的(某物)的最大值应为K-1。除非由于某种原因不可能。
让我们看一下:
for n in range(2, 256):
for k in range(2, n + 1):
m = max(a & b for a in range(1, n + 1) for b in range(a + 1, n + 1) if a & b < k)
t = "*" if m == k - 1 else " "
print("{:s} {:3d} {:3d} {:3d} {:08b} {:08b} {:08b} {:3d} {:3d}".format(t, n, k, m, n, k, m, n - k, k - m))
示例输出:
N K M N K M N-K K-M
----------------------------------------------
2 2 0 00000010 00000010 00000000 0 2
* 3 2 1 00000011 00000010 00000001 1 1
* 3 3 2 00000011 00000011 00000010 0 1
* 4 2 1 00000100 00000010 00000001 2 1
* 4 3 2 00000100 00000011 00000010 1 1
4 4 2 00000100 00000100 00000010 0 2
* 5 2 1 00000101 00000010 00000001 3 1
* 5 3 2 00000101 00000011 00000010 2 1
5 4 2 00000101 00000100 00000010 1 2
* 5 5 4 00000101 00000101 00000100 0 1
* 6 2 1 00000110 00000010 00000001 4 1
* 6 3 2 00000110 00000011 00000010 3 1
6 4 2 00000110 00000100 00000010 2 2
* 6 5 4 00000110 00000101 00000100 1 1
6 6 4 00000110 00000110 00000100 0 2
* 7 2 1 00000111 00000010 00000001 5 1
* 7 3 2 00000111 00000011 00000010 4 1
* 7 4 3 00000111 00000100 00000011 3 1
* 7 5 4 00000111 00000101 00000100 2 1
* 7 6 5 00000111 00000110 00000101 1 1
* 7 7 6 00000111 00000111 00000110 0 1
* 8 2 1 00001000 00000010 00000001 6 1
* 8 3 2 00001000 00000011 00000010 5 1
* 8 4 3 00001000 00000100 00000011 4 1
* 8 5 4 00001000 00000101 00000100 3 1
* 8 6 5 00001000 00000110 00000101 2 1
* 8 7 6 00001000 00000111 00000110 1 1
8 8 6 00001000 00001000 00000110 0 2
* 9 2 1 00001001 00000010 00000001 7 1
* 9 3 2 00001001 00000011 00000010 6 1
* 9 4 3 00001001 00000100 00000011 5 1
* 9 5 4 00001001 00000101 00000100 4 1
* 9 6 5 00001001 00000110 00000101 3 1
* 9 7 6 00001001 00000111 00000110 2 1
9 8 6 00001001 00001000 00000110 1 2
* 9 9 8 00001001 00001001 00001000 0 1
显然,最大值通常为K-1(加星号的行),因此,当它不是K-1时可能更容易找出。另外,最大值似乎是K-1或K-2。
另一项测试,仅在max不是K-1时显示。这次我们先按K排序,然后按N排序。
for k in range(2, 256):
for n in range(k, 256):
m = max(a & b for a in range(1, n + 1) for b in range(a + 1, n + 1) if a & b < k)
if m != k - 1:
print("{:3d} {:3d} {:3d} {:08b} {:08b} {:08b} {:3d} {:3d}".format(n, k, m, n, k, m, n - k, k - m))
然后是输出示例。
N K M N K M N-K K-M
----------------------------------------------
2 2 0 00000010 00000010 00000000 0 2
----------------------------------------------
4 4 2 00000100 00000100 00000010 0 2
5 4 2 00000101 00000100 00000010 1 2
6 4 2 00000110 00000100 00000010 2 2
----------------------------------------------
6 6 4 00000110 00000110 00000100 0 2
----------------------------------------------
8 8 6 00001000 00001000 00000110 0 2
9 8 6 00001001 00001000 00000110 1 2
10 8 6 00001010 00001000 00000110 2 2
11 8 6 00001011 00001000 00000110 3 2
12 8 6 00001100 00001000 00000110 4 2
13 8 6 00001101 00001000 00000110 5 2
14 8 6 00001110 00001000 00000110 6 2
----------------------------------------------
10 10 8 00001010 00001010 00001000 0 2
----------------------------------------------
12 12 10 00001100 00001100 00001010 0 2
13 12 10 00001101 00001100 00001010 1 2
14 12 10 00001110 00001100 00001010 2 2
----------------------------------------------
14 14 12 00001110 00001110 00001100 0 2
----------------------------------------------
16 16 14 00010000 00010000 00001110 0 2
17 16 14 00010001 00010000 00001110 1 2
18 16 14 00010010 00010000 00001110 2 2
19 16 14 00010011 00010000 00001110 3 2
20 16 14 00010100 00010000 00001110 4 2
21 16 14 00010101 00010000 00001110 5 2
22 16 14 00010110 00010000 00001110 6 2
23 16 14 00010111 00010000 00001110 7 2
24 16 14 00011000 00010000 00001110 8 2
25 16 14 00011001 00010000 00001110 9 2
26 16 14 00011010 00010000 00001110 10 2
27 16 14 00011011 00010000 00001110 11 2
28 16 14 00011100 00010000 00001110 12 2
29 16 14 00011101 00010000 00001110 13 2
30 16 14 00011110 00010000 00001110 14 2
----------------------------------------------
18 18 16 00010010 00010010 00010000 0 2
----------------------------------------------
因此,当最大值不是K-1时,它似乎总是K-2,而K必须是偶数。
为了简化起见,请考虑K=2**p
(其中p> 0)(也就是说,即使是K,也要忘记K的较高位)。 “自然”最大值应为K-1,即2**p-1
。
示例:
在二进制中,对于K = 1000,自然最大值为111。但是,如果我们手边的A和B的所有值都小于K,则不可能发生:B的最大值为111,但是那么A必须更小,因此至少会丢失一位。最大值将是110,即K-2。
当N不大于1000时,会出现此问题:如果它足够大,则我们有足够的A和B值来获得A&B = 111。具体来说,如果N至少为1111,那么在A = 111和B = 1111的情况下就完成了。
当K不是2的幂时,它只是稍微复杂一点。
现在,您应该已完成所有必要的操作。
最终检查。
def p2(k):
p = 1
while k % (2 * p) == 0:
p *= 2
return p
count1 = count2 = 0
for k in range(2, 256):
print("-" * 60)
for n in range(k, 256):
m = max(a & b for a in range(1, n + 1) for b in range(a + 1, n + 1) if a & b < k)
t1 = "*" if m == k - 1 else " "
if k % 2 == 0:
p = p2(k)
t2 = "*" if n <= k + p - 2 and m == k - 2 else " "
else:
t2 = " "
if t1 == t2:
count1 += 1
else:
count2 += 1
print("{:s} {:s} {:3d} {:3d} {:3d} {:08b} {:08b} {:08b} {:3d} {:3d}".format(t1, t2, n, k, m, n, k, m, n - k, k - m))
print(count1, count2)
从中学到什么?
最后的注释:为了得到除以K的2的最大幂,我使用了一个循环。有一种更好的方法,您可以考虑使用K^(K-1)
(其中^
会在Python中使用独占或)。
在优化代码时,这种位黑客通常非常有用。您还会找到其他示例here和there。
回答评论
条件可以简化:
总共:
如果N> = K |(K-1),则最大值为K-1,否则为K-2。