LeetCode 46. Permutations
问题链接
题目解析
求解一个无重复元素序列的全排列。
解题思路
什么是全排列?理解一下题意,简单来讲,就是求解序列中元素的所有排列方法,一共有A(n, n)=n!种排列。可以采用递归、非递归、插空等方法求解。
求解全排列参考链接:数组的全排列。
注意:本题中已经说明没有重复元素,对于有重复元素的情况,将在47. Permutations II在给大家说明。
DFS求解全排列
采用DFS,大致算法如下:
- 任意取一个元素放在第一个位置,则有n种选择;
- 再剩下的n-1个元素中再取一个元素放在第二个位置则有n-1种选择,此时可以看做对n-1个元素进行全排列;
- 重复第二步,直到对最后一个元素进行全排列,即最后一个元素放在最后一个位置,全排列结束。
此算法容易理解,但是需要耗费大量的栈空间。每次通过交换nums[index]和nums[i],代表当前选择了nums[i],然后进行下一次选择(DFS),参考代码如下:
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector< vector<int> > res;
DFS(nums, 0, res);
return res;
}
void DFS(vector<int> &nums, int index, vector< vector<int> > &res) {
if(index >= nums.size()) res.push_back(nums);
for(int i = index; i < nums.size(); i++) {
swap(nums[index], nums[i]);
DFS(nums, index+1, res);
swap(nums[index], nums[i]);
}
}
};
非递归求解全排列
还记得LeetCode 31. Next Permutation吗?这道题中求的是序列的下一个序列,本题中其实就是求所有的“下一个序列”。试想一下,如果我不断地求下一个排列,最终我就可以得到所有的排列。
为了避免重复,先将数组排个序,当数组完全逆序时退出循环。关于如何求解全排列,在LeetCode 31. Next Permutation也有具体的过程,这里就不多说了。
直接借用库函数,投机取巧之法:
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector< vector<int> > res;
sort(nums.begin(), nums.end());
do {
res.push_back(nums);
}while(next_permutation(nums.begin(), nums.end()));
return res;
}
};
具体实现全排列,参考代码如下:
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector< vector<int> > res;
sort(nums.begin(), nums.end());
while(1) {
res.push_back(nums);
int n = nums.size(), i = n-2, j = n-1;
while(i >= 0 && nums[i] >= nums[i+1]) i--;
if(i >= 0) {
while(nums[i] >= nums[j]) j--;
swap(nums[i], nums[j]);
}
else break;
reverse(nums.begin()+i+1, nums.end());
}
return res;
}
};
插空法求解全排列
参考大神的帖子:Permutations。了解到这么一种巧妙的方法。
- 当n=1时,数组中只有一个数a1,其全排列只有一种,即为a1;
- 当n=2时,数组中此时有a1a2,其全排列有两种,a1a2和a2a1,那么此时我们考虑和上面那种情况的关系,我们发现,其实就是在a1的前后两个位置分别加入了a2;
- 当n=3时,数组中有a1a2a3,此时全排列有六种,分别为a1a2a3, a1a3a2, a2a1a3, a2a3a1, a3a1a2和 a3a2a1。那么根据上面的结论,实际上是在a1a2和a2a1的基础上在不同的位置上加入a3而得到的。_ a1 _ a2 _ : a3a1a2, a1a3a2, a1a2a3。_ a2 _ a1 _ : a3a2a1, a2a3a1, a2a1a3。
以此类推,可以求得任意n元素的全排列。代码中每次递归取出原数组第一个元素并删除之,利用words保存当前所有排列,然后每个排列中在各个位置插入该元素,参考代码如下:
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
if(nums.empty()) return vector< vector<int> >(1, vector<int>());
vector< vector<int> > res;
int first = nums[0];
nums.erase(nums.begin());
vector< vector<int> > words = permute(nums);
for(auto &a : words) {
for(int i = 0; i <= a.size(); ++i) {
a.insert(a.begin() + i, first);
res.push_back(a);
a.erase(a.begin() + i);
}
}
return res;
}
};
相似题目
LeetCode All in One题解汇总(持续更新中...)
本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.