簡體   English   中英

為什么置換算法的時間復雜度是 n*n! 而不是 n^3 * n!?

[英]Why time complexity for permutation algorithm is n*n! and not n^3 * n!?

作者聲稱這個置換算法的時間復雜度:

from collections import deque

def find_permutations(nums):
    
    nums_l = len(nums)
    perms = deque()
    perms.append([])
    
    for num in nums:                     # (1)
        for _ in range(len(perms)):      # (2)
            perm = perms.popleft() 
            for j in range(len(perm)+1): # (3)
                new_perm = list(perm)    # (4)
                new_perm.insert(j, num)  # (5)
                perms.append(new_perm)   # (6)
    
    return perms

n*n!

但我不明白為什么。 這是我對每一行代碼的時間復雜度的計算:

(1): len(nums) ~ n
(2): len(perms) ~ n!
(3): len(perm) ~ n
(4): n
(5): n
(6): n

所以總時間復雜度為:

n * n! * n * (n + n + n) ~ n^3 * n!

我錯了嗎?

在進入主要問題之前,步驟(6)有一個小錯誤: append是 O(1)。 但這並不影響整體的復雜性。

您的分析在第 (2) 步出錯:

for _ in range(len(perms)):

這不會執行 O(n!) 次迭代。 第一次它甚至只執行1次迭代,第二次仍然是1次迭代,第三次2次迭代,然后2 * 3,然后2 * 3 * 4,......最后一次(n-1)! 迭代。

那么在步驟(3)也存在高估:

for j in range(len(perm)+1)

perm的大小最初很小(對應於步驟 2 的循環):首先排列的大小為 0,然后在外循環的下一次迭代中,它們的大小為 1, ... 然后是 2, ...最多 n-1。

所以對於內循環的迭代次數,我們有這個總和:

1 * 1 + 1 * 2 + 2 * 3 + (2 * 3) * 4 + ... + k! + ... n!

看待這一點的一種更簡單的方法是認識到,在外循環的每次迭代中,此代碼生成的所有排列都比前一次迭代長一個項目。 因此,在第一次迭代中,您將獲得大小為 1(使用第一個輸入值)的所有排列,在第二次迭代中,您將獲得大小為 2(使用兩個第一個輸入值)的所有排列,等等。 這是一種自下而上的方法。 另請注意, popLeft執行正確的次數以刪除前一次(外部)迭代的所有排列,而append執行所有新排列(僅在下一次外部迭代中彈出)。

所以我們現在可以很容易地看到append被執行了這個次數:

1! + 2! + 3! + 4! + ... + n! = O(n!)

如果我們現在將第 4 步的復雜性(“吸收”第 5 步的復雜性)包含在其中,那么我們得到:

1.1! + 2.2! + 3.3! + 4.4! + ... + 唔! = O(nn!)

該算法通過將數字插入現有排列的所有可能位置來生成排列

現在第一個循環顯然是O(n)

讓我們看看其他循環發生了什么:

最后一次迭代(最壞的情況):

  1. 遍歷所有(n-1)! 排列(用之前的迭代生成) - O((n-1)!)
  2. 復制它們中的每一個並在里面添加新數字 - 每個O(n)

總共它的(n-1)! * (n) = n! (n-1)! * (n) = n! 對於其他循環的最壞情況

所以總體來說是O(n * n!)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM