diff --git a/src/combination.rs b/src/combination.rs index 4bd05e6..0c38967 100644 --- a/src/combination.rs +++ b/src/combination.rs @@ -16,6 +16,41 @@ fn binomial(n: usize, k: usize) -> usize { } } +pub fn nth_lex( + mut elements: Vec, + k: usize, + nth: usize, +) -> Result, Box> { + elements.sort(); + let num_elements = elements.len(); + let num_combinations = binomial(num_elements, k); + if nth > num_combinations || k > num_elements || nth == 0 || k == 0 { + return Err(Box::from("Out of bounds")); + } + let mut i = 0; + let mut remaining_k = k; + let mut comb = Vec::new(); + let mut remainder = nth - 1; + while remaining_k > 0 { + // Count the number of combinations that start with elements[i] + // example with n = 5, k = 2 + // nth <= 4 select first + // nth <= 7 select second + // nth <= 9 select third + // nth == 10 select fourth + let count = binomial(num_elements - i - 1, remaining_k - 1); + if remainder < count { + // If the nth combination is within the count, pick this element + comb.push(elements[i].clone()); + remaining_k -= 1; + } else { + remainder -= count; + } + i += 1; + } + Ok(comb) +} + #[derive(Clone)] pub struct Combinator { pub current: Vec, @@ -34,37 +69,6 @@ impl Combinator { idx: 0, }) } - - pub fn nth_lex(mut elements: Vec, k: usize, nth: usize) -> Result, Box> { - elements.sort(); - let num_elements = elements.len(); - let num_combinations = binomial(num_elements, k); - if nth > num_combinations || k > num_elements || nth == 0 || k == 0 { - return Err(Box::from("Out of bounds")); - } - let mut i = 0; - let mut remaining_k = k; - let mut comb = Vec::new(); - let mut remainder = nth - 1; - while remaining_k > 0 { - // Count the number of combinations that start with elements[i] - // example with n = 5, k = 2 - // nth <= 4 select first - // nth <= 7 select second - // nth <= 9 select third - // nth == 10 select fourth - let count = binomial(num_elements - i - 1, remaining_k - 1); - if remainder < count { - // If the nth combination is within the count, pick this element - comb.push(elements[i].clone()); - remaining_k -= 1; - } else { - remainder -= count; - } - i += 1; - } - Ok(comb) - } } impl Iterator for Combinator { diff --git a/src/permutation.rs b/src/permutation.rs index 98e911d..fe7d4cd 100644 --- a/src/permutation.rs +++ b/src/permutation.rs @@ -8,54 +8,54 @@ fn factorial(num: usize) -> usize { fact } +/// Explanation +/// +/// there are 10! possible permutations +/// for each first number there are 9!, for each first 2 numbers 8!, etc. +/// we check how many times we have 9! permutations before we're over 1_000_000 +/// aka. 1000000 / 9! +/// we take the remainder and check how many times we have 8! before we?re over it +/// (1000000 % 9!) 8! +/// etc. +/// every iteration we remove the digit by the idx from the original permutation +/// we only check for 999999 permutations because we already have the first one +/// +pub fn nth_lex(mut digits: Vec, nth: usize) -> Result, Box> { + digits.sort(); + if nth == 1 { + return Ok(digits); + } + if nth > factorial(digits.len()) || nth == 0 { + return Err(Box::from("Out of bounds")); + } + let mut perm = Vec::new(); + let num_unique_digits = digits.len(); + let mut remainder = nth - 1; + for idx in 1..=digits.len() { + let permutations = remainder / factorial(num_unique_digits - idx); + remainder %= factorial(num_unique_digits - idx); + perm.push(digits[permutations].clone()); + digits.remove(permutations); + } + Ok(perm) +} + #[derive(Clone)] -pub struct Permutator { +pub struct Permutator { pub current: Vec, idx: usize, } -impl Permutator { +impl Permutator { pub fn new(elements: Vec) -> Self { Self { current: elements, idx: 0, } } - - /// Explanation - /// - /// there are 10! possible permutations - /// for each first number there are 9!, for each first 2 numbers 8!, etc. - /// we check how many times we have 9! permutations before we're over 1_000_000 - /// aka. 1000000 / 9! - /// we take the remainder and check how many times we have 8! before we?re over it - /// (1000000 % 9!) 8! - /// etc. - /// every iteration we remove the digit by the idx from the original permutation - /// we only check for 999999 permutations because we already have the first one - /// - pub fn nth_lex(mut digits: Vec, nth: usize) -> Result, Box> { - digits.sort(); - if nth == 1 { - return Ok(digits); - } - if nth > factorial(digits.len()) || nth == 0 { - return Err(Box::from("Out of bounds")); - } - let mut perm = Vec::new(); - let num_unique_digits = digits.len(); - let mut remainder = nth - 1; - for idx in 1..=digits.len() { - let permutations = remainder / factorial(num_unique_digits - idx); - remainder %= factorial(num_unique_digits - idx); - perm.push(digits[permutations]); - digits.remove(permutations); - } - Ok(perm) - } } -impl Iterator for Permutator { +impl Iterator for Permutator { type Item = Vec; /// Returns the next permutation and changes the current permutation to it /// This operation wraps around @@ -73,7 +73,7 @@ impl Iterator for Permutator { for idx in 1..=digits.len() { let permutations = remainder / factorial(num_unique_digits - idx); remainder %= factorial(num_unique_digits - idx); - perm.push(digits[permutations]); + perm.push(digits[permutations].clone()); digits.remove(permutations); } self.idx += 1;