“由于超时而终止”

时间:2019-08-19 03:41:20

标签: python python-3.x bitwise-operators

为什么此代码在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 = 4

     

A&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个测试用例中,它引发:'由于超时终止

您能为我解释我错了吗?我该怎么做才能完成所有测试用例?感谢您的帮助!

1 个答案:

答案 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中使用独占或)。 在优化代码时,这种位黑客通常非常有用。您还会找到其他示例herethere


回答评论

  • 如果K为奇数,则由于K <= N,因此可以选择B = K,A = K-1,然后选择A&B = K-1,因此,如果K为奇数,则始终可以获得K-1。并且最大值不能大于K-1,因为它是以下条件之一(A&B的最大值使得A&B
  • 如果K为偶数且N足够大,则可以选择A = K-1,而K = K | (K ^(K-1)),然后选择B = K | (K ^(K-1))。因此,A&B = K-1是可能的,并且不能更大,因此是最大值。
  • 在其他情况下(K为偶数且N不够大),然后选择A = K-2,B = K-1并得到A&B = K-2。正如我在答案中的一个示例中所解释的那样,不可能获得K-1,所以K-2是最大值。

条件可以简化:

  • 首先,K |(K ^(K-1))始终等于K |(K-1)(在两种情况下,我们将LSB侧的所有0都替换为1)。
  • 第二个简化:如果K为奇数,则K | K-1始终等于K,然后N> = K |(K-1)始终成立。因此,只要在所有情况下检查N> = K |(K-1)就足够了,而从不检查K是否为奇数。

总共:

如果N> = K |(K-1),则最大值为K-1,否则为K-2。