Skip to content

Commit 44270b7

Browse files
sozelfistvil02
andauthored
Improve Permutation Implementation (#781)
* ref: improve permutation implementation * ref: permutations of collection of duplicates should be distinct * ref: improve permutation implementation - Add `test_of_all_duplicates` - Update docstring * docs: use slice in doc-str --------- Co-authored-by: Piotr Idzik <[email protected]>
1 parent 72dc88f commit 44270b7

File tree

1 file changed

+120
-42
lines changed

1 file changed

+120
-42
lines changed

src/backtracking/permutations.rs

Lines changed: 120 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,141 @@
1-
/*
2-
The permutations problem involves finding all possible permutations
3-
of a given collection of distinct integers. For instance, given [1, 2, 3],
4-
the goal is to generate permutations like
5-
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], and [3, 2, 1].
6-
This implementation uses a backtracking algorithm to generate all possible permutations.
7-
*/
8-
9-
pub fn permute(nums: Vec<i32>) -> Vec<Vec<i32>> {
10-
let mut result = Vec::new(); // Vector to store the resulting permutations
11-
let mut current_permutation = Vec::new(); // Vector to store the current permutation being constructed
12-
let mut used = vec![false; nums.len()]; // A boolean array to keep track of used elements
13-
14-
backtrack(&nums, &mut current_permutation, &mut used, &mut result); // Call the backtracking function
15-
16-
result // Return the list of permutations
1+
//! This module provides a function to generate all possible distinct permutations
2+
//! of a given collection of integers using a backtracking algorithm.
3+
4+
/// Generates all possible distinct permutations of a given vector of integers.
5+
///
6+
/// # Arguments
7+
///
8+
/// * `nums` - A vector of integers. The input vector is sorted before generating
9+
/// permutations to handle duplicates effectively.
10+
///
11+
/// # Returns
12+
///
13+
/// A vector containing all possible distinct permutations of the input vector.
14+
pub fn permute(mut nums: Vec<isize>) -> Vec<Vec<isize>> {
15+
let mut permutations = Vec::new();
16+
let mut current = Vec::new();
17+
let mut used = vec![false; nums.len()];
18+
19+
nums.sort();
20+
generate(&nums, &mut current, &mut used, &mut permutations);
21+
22+
permutations
1723
}
1824

19-
fn backtrack(
20-
nums: &Vec<i32>,
21-
current_permutation: &mut Vec<i32>,
25+
/// Helper function for the `permute` function to generate distinct permutations recursively.
26+
///
27+
/// # Arguments
28+
///
29+
/// * `nums` - A reference to the sorted slice of integers.
30+
/// * `current` - A mutable reference to the vector holding the current permutation.
31+
/// * `used` - A mutable reference to a vector tracking which elements are used.
32+
/// * `permutations` - A mutable reference to the vector holding all generated distinct permutations.
33+
fn generate(
34+
nums: &[isize],
35+
current: &mut Vec<isize>,
2236
used: &mut Vec<bool>,
23-
result: &mut Vec<Vec<i32>>,
37+
permutations: &mut Vec<Vec<isize>>,
2438
) {
25-
if current_permutation.len() == nums.len() {
26-
// If the current permutation is of the same length as the input,
27-
// it is a complete permutation, so add it to the result.
28-
result.push(current_permutation.clone());
39+
if current.len() == nums.len() {
40+
permutations.push(current.clone());
2941
return;
3042
}
3143

32-
for i in 0..nums.len() {
33-
if used[i] {
34-
continue; // Skip used elements
44+
for idx in 0..nums.len() {
45+
if used[idx] {
46+
continue;
47+
}
48+
49+
if idx > 0 && nums[idx] == nums[idx - 1] && !used[idx - 1] {
50+
continue;
3551
}
3652

37-
current_permutation.push(nums[i]); // Add the current element to the permutation
38-
used[i] = true; // Mark the element as used
53+
current.push(nums[idx]);
54+
used[idx] = true;
3955

40-
backtrack(nums, current_permutation, used, result); // Recursively generate the next permutation
56+
generate(nums, current, used, permutations);
4157

42-
current_permutation.pop(); // Backtrack by removing the last element
43-
used[i] = false; // Mark the element as unused for the next iteration
58+
current.pop();
59+
used[idx] = false;
4460
}
4561
}
4662

4763
#[cfg(test)]
4864
mod tests {
4965
use super::*;
5066

51-
#[test]
52-
fn test_permute() {
53-
// Test case: Generate permutations for [1, 2, 3]
54-
let permutations = permute(vec![1, 2, 3]);
55-
56-
assert_eq!(permutations.len(), 6); // There should be 6 permutations
67+
macro_rules! permute_tests {
68+
($($name:ident: $test_case:expr,)*) => {
69+
$(
70+
#[test]
71+
fn $name() {
72+
let (input, expected) = $test_case;
73+
assert_eq!(permute(input), expected);
74+
}
75+
)*
76+
}
77+
}
5778

58-
// Verification for some of the permutations
59-
assert!(permutations.contains(&vec![1, 2, 3]));
60-
assert!(permutations.contains(&vec![1, 3, 2]));
61-
assert!(permutations.contains(&vec![2, 1, 3]));
79+
permute_tests! {
80+
test_permute_basic: (vec![1, 2, 3], vec![
81+
vec![1, 2, 3],
82+
vec![1, 3, 2],
83+
vec![2, 1, 3],
84+
vec![2, 3, 1],
85+
vec![3, 1, 2],
86+
vec![3, 2, 1],
87+
]),
88+
test_permute_empty: (Vec::<isize>::new(), vec![vec![]]),
89+
test_permute_single: (vec![1], vec![vec![1]]),
90+
test_permute_duplicates: (vec![1, 1, 2], vec![
91+
vec![1, 1, 2],
92+
vec![1, 2, 1],
93+
vec![2, 1, 1],
94+
]),
95+
test_permute_all_duplicates: (vec![1, 1, 1, 1], vec![
96+
vec![1, 1, 1, 1],
97+
]),
98+
test_permute_negative: (vec![-1, -2, -3], vec![
99+
vec![-3, -2, -1],
100+
vec![-3, -1, -2],
101+
vec![-2, -3, -1],
102+
vec![-2, -1, -3],
103+
vec![-1, -3, -2],
104+
vec![-1, -2, -3],
105+
]),
106+
test_permute_mixed: (vec![-1, 0, 1], vec![
107+
vec![-1, 0, 1],
108+
vec![-1, 1, 0],
109+
vec![0, -1, 1],
110+
vec![0, 1, -1],
111+
vec![1, -1, 0],
112+
vec![1, 0, -1],
113+
]),
114+
test_permute_larger: (vec![1, 2, 3, 4], vec![
115+
vec![1, 2, 3, 4],
116+
vec![1, 2, 4, 3],
117+
vec![1, 3, 2, 4],
118+
vec![1, 3, 4, 2],
119+
vec![1, 4, 2, 3],
120+
vec![1, 4, 3, 2],
121+
vec![2, 1, 3, 4],
122+
vec![2, 1, 4, 3],
123+
vec![2, 3, 1, 4],
124+
vec![2, 3, 4, 1],
125+
vec![2, 4, 1, 3],
126+
vec![2, 4, 3, 1],
127+
vec![3, 1, 2, 4],
128+
vec![3, 1, 4, 2],
129+
vec![3, 2, 1, 4],
130+
vec![3, 2, 4, 1],
131+
vec![3, 4, 1, 2],
132+
vec![3, 4, 2, 1],
133+
vec![4, 1, 2, 3],
134+
vec![4, 1, 3, 2],
135+
vec![4, 2, 1, 3],
136+
vec![4, 2, 3, 1],
137+
vec![4, 3, 1, 2],
138+
vec![4, 3, 2, 1],
139+
]),
62140
}
63141
}

0 commit comments

Comments
 (0)