Generate All Permutations of Array in DSA Rust - Time & Space Complexity
When we generate all permutations of an array, we want to know how the time needed grows as the array gets bigger.
We ask: How does the number of steps change when the array length increases?
Analyze the time complexity of the following code snippet.
fn permute(nums: &mut Vec<i32>, start: usize, result: &mut Vec<Vec<i32>>) {
if start == nums.len() {
result.push(nums.clone());
return;
}
for i in start..nums.len() {
nums.swap(start, i);
permute(nums, start + 1, result);
nums.swap(start, i);
}
}
This code generates all possible orderings (permutations) of the input array by swapping elements recursively.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive calls generating permutations by swapping elements.
- How many times: The recursion explores every possible ordering, which is factorial in number of elements.
Each time we add one more element, the number of permutations multiplies by that new number.
| Input Size (n) | Approx. Operations |
|---|---|
| 3 | 6 (3 x 2 x 1) |
| 5 | 120 (5 x 4 x 3 x 2 x 1) |
| 7 | 5,040 (7 x 6 x 5 x 4 x 3 x 2 x 1) |
Pattern observation: The number of operations grows very fast, multiplying by the new input size each time.
Time Complexity: O(n!)
This means the time needed grows very fast as the array gets bigger, because we must check every possible order.
[X] Wrong: "Generating permutations is just like looping through the array once, so it should be O(n)."
[OK] Correct: Each element can be in many positions, so we must explore all combinations, which grows factorially, not linearly.
Understanding this complexity helps you explain why some problems need careful handling when input size grows, showing your grasp of algorithm limits.
"What if we only wanted permutations of length k from n elements? How would the time complexity change?"
Practice
Solution
Step 1: Understand permutations
Permutations are all possible ways to arrange elements in order.Step 2: Apply to array elements
Generating all permutations means listing every possible order of the array elements.Final Answer:
Listing all possible orders of the array elements -> Option AQuick Check:
Permutations = all orders [OK]
- Confusing permutations with sorting
- Thinking permutations remove duplicates
- Assuming permutations find max element
vec![1, 2, 3] using recursion?Solution
Step 1: Identify recursive permutation logic
fn permute(arr: &mut Vec<i32>, start: usize) { if start == arr.len() { println!("{:?}", arr); } else { for i in start..arr.len() { arr.swap(start, i); permute(arr, start + 1); arr.swap(start, i); } } } uses recursion with swapping and backtracking to generate permutations.Step 2: Check other options
Options B, C, and D do not generate permutations; they only print or sort.Final Answer:
fn permute(arr: &mut Vec<i32>, start: usize) { if start == arr.len() { println!("{:?}", arr); } else { for i in start..arr.len() { arr.swap(start, i); permute(arr, start + 1); arr.swap(start, i); } } } -> Option AQuick Check:
Recursive swap + backtrack = fn permute(arr: &mut Vec<i32>, start: usize) { if start == arr.len() { println!("{:?}", arr); } else { for i in start..arr.len() { arr.swap(start, i); permute(arr, start + 1); arr.swap(start, i); } } } [OK]
- Not using mutable reference for swapping
- Missing recursive call
- Printing elements instead of permutations
fn permute(arr: &mut Vec<i32>, start: usize) {
if start == arr.len() {
println!("{:?}", arr);
} else {
for i in start..arr.len() {
arr.swap(start, i);
permute(arr, start + 1);
arr.swap(start, i);
}
}
}
fn main() {
let mut v = vec![1, 2];
permute(&mut v, 0);
}Solution
Step 1: Trace recursive calls for vec![1, 2]
Start at index 0, swap with 0 and 1: - Swap(0,0): [1,2], print when start=2 - Swap(0,1): [2,1], print when start=2Step 2: Confirm output lines
Both permutations [1, 2] and [2, 1] are printed in order.Final Answer:
[1, 2] [2, 1] -> Option BQuick Check:
All permutations of [1,2] printed [OK]
- Expecting only one permutation output
- Confusing swap order
- Assuming compilation error
fn permute(arr: Vec<i32>, start: usize) {
if start == arr.len() {
println!("{:?}", arr);
} else {
for i in start..arr.len() {
let mut arr = arr.clone();
arr.swap(start, i);
permute(arr, start + 1);
}
}
}
fn main() {
let v = vec![1, 2, 3];
permute(v, 0);
}Solution
Step 1: Analyze cloning and mutation
Cloning arr each loop causes performance issues and unnecessary copies.Step 2: Fix by using mutable reference
Passing&mut Vec<i32>allows swapping in place and backtracking without cloning.Final Answer:
Change parameter to mutable reference:arr: &mut Vec<i32>and remove cloning -> Option DQuick Check:
Use mutable reference to avoid cloning [OK]
- Cloning inside loop causes inefficiency
- Not using mutable reference for swaps
- Thinking adding mut to main vector fixes logic
vec![1, 2, 2], how many unique permutations will the standard recursive swap method print without filtering duplicates?Solution
Step 1: Calculate total permutations without filtering
For 3 elements, total permutations = 3! = 6.Step 2: Consider duplicates in array
Standard recursive swap method does not filter duplicates, so all 6 permutations including duplicates print.Final Answer:
6 -> Option CQuick Check:
3! = 6 permutations printed [OK]
- Assuming duplicates reduce output automatically
- Confusing unique permutations with total permutations
- Thinking output is 3 or 2 without filtering
Ready to prove it?
Pass the test and this pattern moves unknown
