Permutations medium
Problem Statement
Given an array nums
of distinct integers, return all the possible permutations. You can return the answer in any order.
Example 1
Input: nums = [1,2,3] Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Example 2
Input: nums = [0,1] Output: [[0,1],[1,0]]
Steps
-
Backtracking: We'll use backtracking to explore all possible permutations. Backtracking is a recursive algorithm that explores all possible combinations by making a choice, exploring the consequences, and then undoing that choice to explore other options.
-
Base Case: If the current permutation has the same length as the input array, we've found a complete permutation, so we add it to the result.
-
Recursive Step: For each element in the input array that hasn't been used in the current permutation, we:
- Add the element to the current permutation.
- Recursively call the function to explore permutations with the added element.
- Remove the element from the current permutation (backtracking step) to explore other possibilities.
Explanation
The code uses a recursive helper function permuteHelper
. It takes the input array nums
, a vector currentPermutation
to build the permutations, and a vector used
to track which elements have already been used in the current permutation.
-
Initially,
permuteHelper
is called with an emptycurrentPermutation
andused
vector filled withfalse
(indicating no elements are used). -
In each recursive call, it iterates through
nums
. If an element is not used (!used[i]
), it's added tocurrentPermutation
, marked as used (used[i] = true
), and the function recursively calls itself. -
After the recursive call returns, the element is removed from
currentPermutation
and marked as unused (used[i] = false
), allowing exploration of other permutations. -
When
currentPermutation
's size equalsnums
's size, a complete permutation is found, and it's added to the result.
Code
#include <vector>
#include <algorithm>
class Solution {
public:
std::vector<std::vector<int>> permute(std::vector<int>& nums) {
std::vector<std::vector<int>> result;
std::vector<int> currentPermutation;
std::vector<bool> used(nums.size(), false);
permuteHelper(nums, currentPermutation, used, result);
return result;
}
private:
void permuteHelper(std::vector<int>& nums, std::vector<int>& currentPermutation, std::vector<bool>& used, std::vector<std::vector<int>>& result) {
if (currentPermutation.size() == nums.size()) {
result.push_back(currentPermutation);
return;
}
for (int i = 0; i < nums.size(); ++i) {
if (!used[i]) {
used[i] = true;
currentPermutation.push_back(nums[i]);
permuteHelper(nums, currentPermutation, used, result);
currentPermutation.pop_back(); // Backtrack: remove the last element
used[i] = false; // Backtrack: mark the element as unused
}
}
}
};
Complexity
- Time Complexity: O(n * n!), where n is the number of elements in the input array. There are n! permutations, and each permutation takes O(n) time to construct and add to the result.
- Space Complexity: O(n), primarily due to the recursive call stack and the
currentPermutation
vector. In the worst case, the depth of the recursion is n. Theused
vector also takes O(n) space.