
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
numsare 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
numshas 3 elements, there should be3! = 6permutations. 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
720permutations (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 functionfindPermutationspassing 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
generatePermutationsmethod initializes an empty list calledresultthat will eventually hold all permutations as lists of integers. It calls thepermuteHelpermethod, passing it an empty list (current permutation), theresultlist, and theelementsarray which contains the integers to permute.The recursive method
permuteHelperdetermines when a permutation is complete (when the size of the current list equals the size of theelementsarray) and adds it to theresultlist. For permutation generation, the method iterates over each element in theelementsarray. If the element is not already in the current permutation represented bycurrent, it is added, andpermuteHelperis 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_permutationsfunction 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_arrayto prevent memory leakage.
Usage Example:
- Call
permute_arraywith 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
resultsto store the resulting permutations. - Define a recursive function
recursethat:- Checks if the length of the current permutation
currentis equal to the length ofelements. If so, it adds a copy ofcurrenttoresults. - Iterates over each element in
elementsto 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
recursewith an empty array. - Return the
resultsarray 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
permutemethod, the approach involves defining an inner recursive functiongenerate_permutationsthat builds permutations by choosing numbers not currently in the permutation being constructed.Initialization of an empty list
resultis 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
resultlist 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.