【问题标题】:My Codekata solution delivers the correct solution, but runs into performance Issues during final test-cases我的 Codekata 解决方案提供了正确的解决方案,但在最终测试用例中遇到了性能问题
【发布时间】:2019-09-24 21:29:16
【问题描述】:

我在 python3 中完成了我的算法,以解决 codewars.com 上的“codekata”。(https://www.codewars.com/kata/odder-than-the-rest-1/train/python) 我的代码正确并以足够的速度解决了初始测试用例。但是,在提交最终测试时,代码会因为解决给定任务的时间过长而超时。

最初,我将 for 循环的内容实现为一个名为“calculate_oddness_level”的分离函数。我发现这可能比在 for 循环中执行要慢一些,所以我就这样做了。

我知道在 for 循环中执行 while 循环并不是最佳性能。我多次思考如何避免这种情况。但是,我需要确定列表中每个奇数的“奇数”级别。为了确定“级别”,需要一个循环,并且似乎比递归更快。因此,除了在 for 循环中运行 while 循环之外,似乎别无选择。但是,我立即将所有偶数分配为“奇数级”0,从而消除了所有偶数的运行循环。

因此,我不知道如何才能在性能上取得任何显着提升。

def oddest(a):
        if len(a) == 0: return None
        list_of_oddness_levels = []
        for n in a:
                if n % 2 == 0:
                     list_of_oddness_levels.append(0)
                else :
                    level = 1
                    while True:
                        n = (n-1)/2
                        if n % 2 == 0 or n % 1 != 0:
                                break
                        else:
                                level += 1
                    list_of_oddness_levels.append(level)
                print("adding Level!")
        maximum = max(list_of_oddness_levels)
        index_of_maximum = list_of_oddness_levels.index(maximum)

        if list_of_oddness_levels.count(maximum) > 1:
                return None
        else:
                return a[index_of_maximum]

根据最初的测试用例,我的代码应该能正确解决任务。然而,它似乎运行得很慢,因为它在最终提交期间遇到了超时错误。

我知道,可能有一些简单的数学解决方案或一些 5 行高级代码利用一些我不知道的 python3 库或特殊函数。然而,一个详细的、一步一步的、尽可能具有描述性的“干净代码”解决方案将是首选。

【问题讨论】:

标签: python algorithm numbers


【解决方案1】:
  • 您不需要列表,只需 O(1) 额外空间即可。

  • 问题可能不是您的实现,而是 -1。为什么?它是无限奇数,因为 (-1 - 1) / 2 = -1。有趣的是,这是唯一一个这样的数字,所有其他负数的奇数级别都是 1。

  • 对于正数,您基本上是从右侧计算设置为 1 的连续位的数量,因此您可以更快地使用掩码。

假设 32 位整数(对不起 Java),这就是这样的实现的样子:

public Integer oddest(int[] a) {
    if (a == null || a.length == 0)
        return null;
    // create the 31 masks needed, the left-most bit is only set for negative numbers
    int[] masks = new int[31];
    masks[0] = 1;
    for (int i = 1; i < 31; i++)
        masks[i] = (masks[i - 1] << 1) | 1; // masks[i - 1] * 2 + 1
    int bestNumber = 0;
    int bestLevel = 0;
    boolean conflict = true;
    for (int n : a) {
        int level = 0;
        if (n == -1) {
            return -1;
        } else if (n & 1 == 1) { // number is odd
            if (n < 0) {
                level = 1;
            } else {
                // now use the masks and bisection to find the oddity of positive numbers
                int left = 0; // finally at the index of best matching mask
                int right = 31; // never reached, finally left + 1
                while (left + 1 < right) {
                    int mid = (left + right) >> 1;
                    if (n & masks[mid] == masks[mid])
                        left = mid;
                    else
                        right = mid;
                }
                level = right;
            }
        }
        if (level > bestLevel) {
            bestNumber = n;
            bestLevel = level;
            conflict = false;
        } else if (level == bestLevel && n != bestNumber) {
            conflict = true;
        }
    }
    if (conflict)
        return null;
    return bestNumber;
}

【讨论】:

  • 感谢您的时间、提示和代码示例。问题确实是“-1”。我刚刚通过将任何数字的奇数级别在某个点下降到 -1 分配给“999”来解决它。至此,最终的测试用例很快就完成了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 2010-11-06
  • 1970-01-01
  • 2022-10-31
  • 2019-06-18
相关资源
最近更新 更多