I've been wondering about the time complexity of some of Ruby's built-in methods, these two in particular. I think the best I've been able to come up with for a permutation method on my own is Θ(n · n!), does Ruby's built-in perform better? If so, please help me understand their algorithm.
Array#permutation returns an Enumerator with n! Arrays, so the time complexity will be at least O(n!).
I wrote this method :
def slow_method(n)
(1..n).to_a.permutation.each do |p|
p
end
end
It doesn't do anything with p, expect forcing the generation of all the permutations. Building an Array of all the permutations would use too much memory.
This method was called 10 times for n between 10 and 13, and the average times in seconds were :
t10 = 0.618895
t11 = 6.7815425
t12 = 82.896605
t13 = 1073.015602
O(n!) looks like a reasonable approximation :
t13/fact(13)*fact(12)/t12 #=> 0.995694114280165
t13/fact(13)*fact(11)/t11 #=> 1.0142685297667369
t13/fact(13)*fact(10)/t10 #=> 1.0103498450722133
O(n*n!) doesn't :
t13/(fact(13)*13)*fact(12)*12/t12 #=> 0.9191022593355369
t13/(fact(13)*13)*fact(11)*11/t11 #=> 0.8582272174949312
t13/(fact(13)*13)*fact(10)*10/t10 #=> 0.777192188517087
The generation seems to be O(n!), but doing anything with the generated Arrays would bring the overall complexity to O(n*n!).
Why isn't the generation O(n*n!)? It could come from the fact that when recursively generating [1,2,3,4,5].permutation, the remaining permutations are the same for [1,2] and [2,1].
O(n!) is already so slow that n will never be much bigger than 10, so O(n*n!) isn't much worse. For n=20, n! is 2432902008176640000 and n*n! is 48658040163532800000.
[1,2,...n].repeated_permutation(k) generates n**k Arrays of k elements.
The complexity should be either O(n**k) or O(k*n**k).
For k=n, it becomes O(n**n) or O(n**(n+1)), which is even (much) worse than for permutation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With