【问题标题】:Time and Space Complexity of a Recursive Algorithm递归算法的时间和空间复杂度
【发布时间】:2020-11-09 16:20:41
【问题描述】:

n 转换为其英文单词表示,其中 0 n

Python 解决方案:

class Solution:
    def helper(self, n):
        ones = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine']
        teens = ['Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen']
        tens = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety']

        res = ''
        if n < 10:
            res = ones[n]
        elif n < 20:
            res = teens[n - 10]
        elif n < 100:
            res = tens[n // 10] + ' ' + self.helper(n % 10)
        elif n < 1000:
            res = self.helper(n // 100) + ' Hundred ' + self.helper(n % 100)
        elif n < 1000000:
            res = self.helper(n // 1000) + ' Thousand ' + self.helper(n % 1000)
        elif n < 1000000000:
            res = self.helper(n // 1000000) + ' Million ' + self.helper(n % 1000000)
        return res.strip()


    def convert_to_word(self, n):
        if n == 0:
            return 'Zero'
        return self.helper(n)

我一直在尝试计算这个解决方案的时间和空间复杂度。我看到了不同的答案。有人说时间复杂度是 O(1),因为辅助函数被调用的次数是固定的(即使 n 是一个很大的数)。其他人说它是 O(log(n))。

空间复杂度好像是O(1)?

我很困惑。请帮我澄清一下。谢谢。

【问题讨论】:

    标签: time-complexity space-complexity


    【解决方案1】:

    在大于 1000000000 的所有输入 n 上,该函数立即返回一个空字符串,无需任何计算或递归调用。因此,时间复杂度当然是 O(1),空间复杂度也是如此(因为较小的 n 发生的情况完全不相关)。

    如果您删除该行,情况会有所不同并且更有趣

    elif n < 1000000000
    

    所以对于大的n,你会得到一个(实际上)无限的结果字符串,其中包含无限数量的Million-子字符串(忽略整数在真实计算机上具有最大大小的事实,并忽略以下事实:你会得到无意义的数字词)。在这种情况下,您将获得时间复杂度O(log(n)^2)(因为您要连接长度为O(log n) 的字符串O(log n))和空间复杂度O(log n)(因为递归调用的调用堆栈)。通过更有效地处理字符串连接,时间复杂度可以轻松降低到O(log n)


    一些补充说明

    从 cmets 看来,为什么时间复杂度为 O(1) 并不明显。如果我们说时间复杂度T(n)在O(1),那就意味着存在一个常数c和一个常数k 这样对于所有 n > kT(n) .

    在这个例子中,选择c = 9k = 0 可以解决问题,或者选择c = 1 and k = 1000000000,因此时间复杂度为 O(1)。现在还应该清楚的是,以下函数也是 O(1)(尽管隐藏常数因子非常大):

    void f(int n) {
       if (n < 1000000000) {
          for(int i = 0; i < n; i++) { 
             for(int k = 0; k < n; k++)
                print(i); 
          }
       }
       else print("");
    }
    

    【讨论】:

    • 感谢您的回复。比方说,如果我更有效地处理字符串连接(追加/扩展到列表,然后加入这些字符串),算法是否需要 O(log n) 时间(O(log n)字符串连接 + O(log n) 用于递归调用 = O(log n) 总体)和 O(log n) 空间(用于递归调用)?例如,如果 n = 999,999,999。
    • 是的,但前提是您删除了n 上的最后一个条件,否则为 O(1)。
    • 为什么是 O(1)?如果 n 大于最后一个条件,那么,是的,我们马上返回,它是 O(1)。但我可以有不同的输入,对吧?如果我删除 n 上的最后一个条件,我仍然可以有不同的输入。例如,如果我删除最后一个条件并且输入将是 999,999,那么我将对辅助函数进行多次递归调用。不会花费 O(log n) 时间吗?
    • 是的,这就是我所说的:如果您删除最后一个条件并更有效地加入字符串,那就是 O(log n) 时间。
    • 很抱歉给您带来了困惑。你是说如果我不会删除最后一个条件并且我的输入将是例如 999,999,那么时间复杂度将为 O(1)?
    猜你喜欢
    • 2023-03-04
    • 2015-05-13
    • 1970-01-01
    • 2011-02-12
    • 2019-04-21
    相关资源
    最近更新 更多