
Problem Statement
The task requires generating all possible permutations of a given array of distinct integers, nums
. A permutation of an array is a rearrangement of its elements. You are to return the permutations in any order. Each integer in the array is unique and can range from -10 to 10.
Examples
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]]
Example 3
Input:
nums = [1]
Output:
[[1]]
Constraints
1 <= nums.length <= 6
-10 <= nums[i] <= 10
- All the integers of
nums
are unique.
Approach and Intuition
Understanding Permutations
Permutations involve arranging elements of a set in all possible orders. For an array nums
of length n
, there are n!
(factorial of n
) permutations. The factorial function usually grows very quickly, which informs our constraints on the maximum array length.
Example Analysis
Example 1:
- Input:
nums = [1,2,3]
- Output: All permutations of
[1,2,3]
. - As
nums
has 3 elements, there should be3! = 6
permutations. These include arrangements such as[1,2,3]
, where we start with 1 and permute 2 and 3, and[2,1,3]
, where we start with 2 and permute 1 and 3.
- Input:
Example 2:
- Input:
nums = [0,1]
- Output: The permutations are
[0,1]
and[1,0]
. - These are straightforward as the array has only two elements, so swapping them gives the permutations.
- Input:
Example 3:
- Input:
nums = [1]
- Output:
[[1]]
- With only one element, the only "permutation" is the element itself.
- Input:
Generation Techniques
Backtracking Algorithm:
- Recursively choose an element to be the next in the permutation sequence.
- Use a temporary structure (like a list or a set) to keep track of what elements have been used.
- Backtrack once you have considered all elements for the current sequence.
Iterative Algorithms:
- Techniques like Heap's Algorithm can be used to generate permutations by swapping elements systematically.
Given the constraints:
- Maximum array length is 6, so at most we are generating
720
permutations (6!). - Elements are within a small integer range and are guaranteed unique, simplifying checks and swaps.
Each method suits different scenarios and complexities, especially when considering the reusability of elements and the cost of recursion or iteration control structures for higher factorial values.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
vector<vector<int>> generatePermutations(vector<int>& elements) {
vector<vector<int>> result;
vector<int> permutation;
findPermutations(permutation, result, elements);
return result;
}
void findPermutations(vector<int>& permutation, vector<vector<int>>& result, vector<int>& elements) {
if (permutation.size() == elements.size()) {
result.push_back(permutation);
return;
}
for (int element : elements) {
if (find(permutation.begin(), permutation.end(), element) == permutation.end()) {
permutation.push_back(element);
findPermutations(permutation, result, elements);
permutation.pop_back();
}
}
}
};
The provided C++ program features a class named Solution
that includes two primary functions to generate all possible permutations of a given array of integers. The main approach utilizes backtracking, which is a common technique for such permutation problems.
Here’s a brief breakdown of each function within the class:
generatePermutations: This function initializes the necessary containers for the problem—a result container
vector<vector<int>>
for storing all permutations and a temporaryvector<int>
to hold the current permutation. It then calls the helper functionfindPermutations
passing these initialized containers along with the input vectorelements
.findPermutations: A recursive function that generates permutations. The base case checks if the size of the temporary permutation vector matches the size of the input vector
elements
. If they match, it means a complete permutation is formed and this permutation is added to the result container. The function then iterates over each element in the input vector, checking if the element is already included in the current permutation to ensure no duplicates. If the element is not in the current permutation, it’s added, and the function recursively calls itself. Once the call returns, the element is removed (backtracked), allowing for the subsequent permutations to be formed correctly.
Make sure to include the necessary headers before implementing this class, such as #include <vector>
and #include <algorithm>
to handle the C++ Standard Library containers and functions used in the code.
class Solution {
public List<List<Integer>> generatePermutations(int[] elements) {
List<List<Integer>> result = new ArrayList<>();
permuteHelper(new ArrayList<>(), result, elements);
return result;
}
public void permuteHelper(
List<Integer> current,
List<List<Integer>> result,
int[] elements
) {
if (current.size() == elements.length) {
result.add(new ArrayList<>(current));
return;
}
for (int element : elements) {
if (!current.contains(element)) {
current.add(element);
permuteHelper(current, result, elements);
current.remove(current.size() - 1);
}
}
}
}
This code in Java is designed to generate all permutations of a given array of integers. The main class, named Solution
, contains a method generatePermutations
which utilizes a helper method permuteHelper
to facilitate the recursive generation of permutations.
Here's a breakdown of how the solution operates:
The
generatePermutations
method initializes an empty list calledresult
that will eventually hold all permutations as lists of integers. It calls thepermuteHelper
method, passing it an empty list (current permutation), theresult
list, and theelements
array which contains the integers to permute.The recursive method
permuteHelper
determines when a permutation is complete (when the size of the current list equals the size of theelements
array) and adds it to theresult
list. For permutation generation, the method iterates over each element in theelements
array. If the element is not already in the current permutation represented bycurrent
, it is added, andpermuteHelper
is recursively called with this new state. After the recursive call, the last added element is removed to backtrack and explore other permutations.
This code effectively captures all permutations by ensuring each integer is considered for each position in the permutation, provided it's not already included. The use of recursion coupled with backtracking allows the exploration of all possible configurations of the given integers, ensuring comprehensive permutation generation.
void generate_permutations(int* elements, int total_elements, int* current_permu, int curr_size, int** results,
int* countResults) {
if (curr_size == total_elements) {
results[*countResults] = malloc(sizeof(int) * total_elements);
memcpy(results[*countResults], current_permu, total_elements * sizeof(int));
*countResults += 1;
return;
}
for (int pos = 0; pos < total_elements; pos++) {
bool already_used = false;
for (int prev = 0; prev < curr_size; prev++) {
if (current_permu[prev] == elements[pos]) {
already_used = true;
break;
}
}
if (!already_used) {
current_permu[curr_size] = elements[pos];
generate_permutations(elements, total_elements, current_permu, curr_size + 1, results, countResults);
}
}
}
int** permute_array(int* elements, int len, int* size_result_set,
int** size_results) {
int** permutations = (int**)malloc(sizeof(int*) * 10000);
*size_results = (int*)malloc(sizeof(int) * 10000);
for (int i = 0; i < 10000; i++) {
(*size_results)[i] = len;
}
*size_result_set = 0;
int* temp_permu = (int*)malloc(len * sizeof(int));
memset(temp_permu, -1, len * sizeof(int));
generate_permutations(elements, len, temp_permu, 0, permutations, size_result_set);
free(temp_permu);
return permutations;
}
The provided C code defines a function for generating all possible permutations of a given integer array. Below is an overview of the solution:
Function Definitions:
generate_permutations
—Recursive function that builds permutations.permute_array
—Initializes the process and gathers results.
How It Works:
- In
permute_array
, memory allocation occurs for storing permutations and a temporary array (temp_permu
) is used for constructing permutations. - The
generate_permutations
function then recursively generates permutations by trying each element in the current position and checking if it has been used already in the permutation being constructed. - Once a permutation of the required size is formed, it is stored in the results and the count of results is incremented.
- In
Memory Management:
- Dynamic memory is allocated for permutations and the temporary array. Ensure to manage this memory properly to avoid leaks, especially in large-scale uses or modifications of this function.
- After recursion, occupied memory for the temporary array is freed in
permute_array
to prevent memory leakage.
Usage Example:
- Call
permute_array
with the array of integers you want to permute along with its length, and retrieve the collection of permutations and their size. - The function will return a pointer to an array of integer pointers, each pointing to an array that represents a permutation.
- Call
This approach is effective for generating permutations in a systematic manner without redundancies, owing to the use of the already_used
flag that avoids reusing elements in a single permutation. When implementing or modifying this logic, ensure proper error handling and boundary checks for robustness, especially when handling the potential large allocations for storing permutations.
var generatePermutations = function (elements) {
var results = [];
var recurse = function (current) {
if (current.length === elements.length) {
results.push([...current]);
return;
}
for (var element of elements) {
if (!current.includes(element)) {
current.push(element);
recurse(current);
current.pop();
}
}
};
recurse([]);
return results;
};
The given JavaScript function generatePermutations
is designed to calculate all possible permutations of a given list of elements. The process is as follows:
- Declare an array
results
to store the resulting permutations. - Define a recursive function
recurse
that:- Checks if the length of the current permutation
current
is equal to the length ofelements
. If so, it adds a copy ofcurrent
toresults
. - Iterates over each element in
elements
to expand the current permutation:- If the element is not already in
current
, add it, recurse, and then remove it to backtrack.
- If the element is not already in
- Checks if the length of the current permutation
- Initiate the recursive process by calling
recurse
with an empty array. - Return the
results
array containing all permutations.
This implementation uses a backtracking approach to explore all possible combinations by adding elements one by one, and removing them (backtracking) once all permutations for that specific prefix are found. The use of array operations like push
, pop
, and includes
facilitates the management of the current permutation's state during the recursion.
class Solution:
def permute(self, numbers: List[int]) -> List[List[int]]:
def generate_permutations(current):
if len(current) == len(numbers):
result.append(current.copy())
return
for number in numbers:
if number not in current:
current.append(number)
generate_permutations(current)
current.pop()
result = []
generate_permutations([])
return result
The Python3 solution provided addresses the problem of generating all permutations of a list of numbers.
Working with the
permute
method, the approach involves defining an inner recursive functiongenerate_permutations
that builds permutations by choosing numbers not currently in the permutation being constructed.Initialization of an empty list
result
is done to store all the permutations. The recursion starts with an empty list representing the initial state of the permutation.During each recursive call:
- If the current list is equal in length to the input list
numbers
, it signifies a complete permutation, which is then added to theresult
. - The function iterates over each number in the input list
numbers
. - For each number, if it is not already in the current list (to avoid repetition), it gets added, and the function recurses deeper with this new state.
- After recursion returns, the last added element is removed (backtracking), allowing for exploration of different numbers to add next.
- If the current list is equal in length to the input list
The function returns the
result
list once all permutations have been explored and compiled. This technique effectively employs recursive backtracking to address the permutation problem, ensuring that all possible combinations of the list elements are considered without repetition of elements within a permutation.
No comments yet.