I require a method for taking in a string of varying length and content, returning the number of permutations without repetition. I have written the following to try to solve this problem
def permutations(n)
k = n.to_s.chars.uniq.length
e = n.to_s.length
m = (1..e).reduce(1, :*)
p = (1..k).reduce(1, :*)
l = m / p
case
when k == 1 then 1
when k < e then l
else m
end
end
The above is returning some results that I've been confused by for a couple of days which I've realised occur where there are more than 1 set of duplicate values for uniq
to check.
If I pass through bbbb789
I get 210
which is correct. However if I have a set with two duplicates such as 73839
the expected result is 60 but I reach 5
I realised yesterday where the issues were but I can't find a way to factor in the duplicates
Also my first method for solving this was to use
k = n.to_s.chars.uniq.length
m = n.to_s.chars.length
return 1 if k <= 1
n.to_s.chars.permutation(m)to_a.uniq.size
This also worked but takes an age to cycle through all permutations of longer sets
TL;DR:
def factorial(n)
(1..n).inject(1, :*)
end
str = '73839'
# https://stackoverflow.com/questions/5470725/how-to-group-by-count-in-array-without-using-loop
chars_count = str.split('').inject(Hash.new(0)) { |h, e| h[e] += 1 ; h }
# https://stackoverflow.com/questions/9560335/ruby-hash-to-array-of-values
chars_fact = chars_count.values.inject(1) {|result, element| result*factorial(element)}
p "There are #{factorial(str.length)/chars_fact} permutations without duplicates."
Not very good explanation :
Well, this is mostly a math problem:
Note : When I write n! you should read "factorial n" and it represents the integer 1*2*...*n . You can find a ruby implementation here : https://stackoverflow.com/a/12415362/4480140
If you had na's and mb's then the formula to find the number of permutations without duplicates is n choose m+n which is (m+n)!/(n!*m!).
Then, what we do if we have 'aazzerty' is we say we have a's and b's. So we have 'aabbbbbb', we have 2 choose 8 ways of permuting. One of the possible permutations would be 'bbabbbab'. Then we permute the b's. We know that these b's contain 2 z's and 1 of (e,r,t,y). We will permute everything that is not az or an a. We have 2 choose 6 ways of doing that. We repeat the process ...
In the end the number of permutations is (2 choose 8) (2 choose 6) (1 choose 4) ... (1 choose 2). We can cancel out, in fact we get 8!/(2!*2!*1!*1!*1!*1!).
Basically, we have to count the number of each character, take the factorial of all those numbers, multiply them together. That's the denominator, and the numerator is factorial the length of the string.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.