【问题标题】:Why do these python and kotlin functions perform differently on hackerrank?为什么这些 python 和 kotlin 函数在hackerrank 上的表现不同?
【发布时间】:2020-07-02 17:22:12
【问题描述】:

我正在尝试使用 Kotlin 解决关于 Hackerrank(Hack the Interview II - Global Product Distribution)的竞赛挑战

我开始感到恼火,因为我的代码总是通过少量输入的测试用例而在较大的输入上失败,甚至在一个输入上超时。

于是我上网找到thispython 代码,它巧妙地解决了所有的测试用例。我什至将 Python 代码行转换为 Kotlin。但我的 Kotlin 代码始终保持与以前一样的糟糕性能。

这是两段代码。

Python:

def maxScore(a, m):

    a.sort()
    print(a)
    x=len(a)
    
    if x%m==0:
        y=int(x/m)
    else:
        y=int(x/m)-1
    
    summ=0
    count=1
    #print(y)
    i=0
    for _ in range(y): 
        summ=summ+(sum(a[i:i+m])*count)
        count=count+1
        i=i+m
        print(summ)
    
    summ=summ+sum(a[i:])*count
    print(summ)
    
    return summ%1000000007

科特林:

fun maxScore(a: Array<Int>, m: Int): Int {

    a.sort()

    // print(a)

    val x = a.size

    val y = if (x % m == 0) x / m
        else (x / m) - 1

    var summ = 0
    var count = 1

    // print(y)

    var i = 0

    for (s in 0 until y) {
        summ += a.sliceArray(i until (i + m)).sum() * count
        count++
        i += m
        // print(summ)
    }

    summ += a.sliceArray(i until a.size).sum() * count
    // print(summ)

    return summ % 1000000007

}

代码翻译有问题吗?如何让 Kotlin 代码在更大的测试用例上工作?

更新:copyOfRange() 的性能优于 sliceArray()。代码不再在任何测试用例上超时,但在所有大型测试用例上仍然失败

【问题讨论】:

  • 我的猜测是 Python 优化了 sum(array[i:i+m]) 而 Kotlin 没有优化类似的 slice 和 sum 函数。
  • @Barmar 没有解释为什么大型测试用例的输出不同
  • 从文档来看,sliceArray() 似乎分配了一个新数组并复制了一些东西,但 Python 可能适用于引用。 (并且可能存在整数溢出,这在 Python 中不会发生)
  • 你能澄清一下 - 你的 Kotlin 程序是慢还是它也得到了错误的答案?它似乎没有考虑 32 位整数的溢出问题,这几乎可以肯定在后面的测试用例中进行了测试。

标签: python performance kotlin


【解决方案1】:

我可以在这里看到三个问题。我现在会为你指明正确的方向。

  1. Python 和 Kotlin 每次都会复制数组。这可能是也可能不是问题。您有多达一百万个元素,每个元素只复制一次。如果这超出了您的时间限制,我会感到惊讶,但它可能会这样做。看来您可以使用.subList() 避免复制。

  2. 您似乎将剩余的物品视为在自己的垃圾箱中。但是这个 bin 比 m 小,这是不允许的。检查这是否真的是您想要的。

  3. Kotlin Ints 是 32 位有符号整数。在溢出之前,您最多只能存储大约 20 亿个数字。你需要避免这种情况!看看限制 - 你可以拥有多达一百万种产品,每个产品的价值高达十亿。 (这与 Python 整数不同,它永远不会溢出,因此总是会给出正确的答案,但是如果您尝试对非常大的数字进行操作,可能会占用大量内存并减慢速度,这很可能会导致您的程序超时。)这里有一个提示:(a + b) % n 等于 ((a % n) + (b % n)) % n

【讨论】:

  • y的计算保证了剩余物品的数量永远不会小于m
  • 对于您提出的第三点,我在计算 summ 时尝试使用提示的右侧,并且性能没有什么不同
  • 提示不是简单的替换。您需要考虑在您的程序中数字可能溢出的位置。尝试使用由非常大的数字组成的测试数据单步执行您的代码,以了解会发生什么。例如。如果产品的值为 999999997、999999998、999999999、1000000000,会发生什么?如果 n=1000000,m=1 并且每个产品的值都是 1000000000,会发生什么?想想你的算术可能在哪里溢出以及如何避免它。
猜你喜欢
  • 2013-02-23
  • 2019-12-05
  • 1970-01-01
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
  • 1970-01-01
  • 2012-08-07
相关资源
最近更新 更多