题目:
Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3]
have the following permutations:
[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
思路:
1、递推法:如果我们知道了数组中前i个元素的所有permutations,那么如何产生前i+1个元素的所有permutations呢?就是对于前i个元素的每一个permutation,我们在[0, permutation.size()]的任意位置上插入第i+1个元素,就可以产生一个新的独一无二的permutation。这个思路挺直观,但是请见下面实现中的小trick,可以让运行效率更高(仅在[0, permutation.size())的位置插入第i+1个元素,而对在permutation.size()位置上的插入,则通过修改已有元素实现)。
2、调用next_permutation:我们在前面已经实现了next_permutation,对于个数为n的数组,其所有permutations的数量为n!。那么我们首先产生一个permutation,然后连续产生n! - 1次next_permutation,即可生成所有的permutation。
代码:
1、递推法:
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> lists;
vector<int> list = {nums[0]};
lists.push_back(list);
for(int i = 1; i < nums.size(); ++i) // add the i-th element to the current result
{
// generate the new permutations
int current_size = lists.size();
for(int j = 0; j < current_size; ++j) // generate the new permute from the j-th permute
{
for(int k = 0; k < lists[j].size(); ++k) // think why we make k < lists[j].size() rather than k <= lists[j]?
{
vector<int> permutation;
permutation.insert(permutation.end(), lists[j].begin(), lists[j].begin() + k);
permutation.push_back(nums[i]);
permutation.insert(permutation.end(), lists[j].begin() + k, lists[j].end());
lists.push_back(permutation);
}
}
for(int j = 0; j < current_size; ++j) // modify existing results to avoid reallocation of vector space
lists[j].push_back(nums[i]);
}
return lists;
}
};
2、next_permutation法:
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> ret;
sort(nums.begin(), nums.end());
ret.push_back(nums);
while(nextPermutation(nums))
ret.push_back(nums);
return ret;
}
private:
bool nextPermutation(vector<int>& nums) {
int len = nums.size(), i = len - 1;
if(len == 0)
return false;
while(i > 0 && nums[i-1] >= nums[i]) // try to find the first increasing pair
i--;
if(i == 0) // not found, so reverse the whole array
{
reverse(nums.begin(), nums.end());
return false;
}
int right = i;
while(right < len && nums[right] > nums[i - 1]) // find the last element that is larger than nums[i-1]
right++;
swap(nums[i-1], nums[right - 1]);
reverse(nums.begin() + i, nums.end()); // we do not need to sort, just reverse
return true;
}
};