一 题目
Given a collection of distinct integers, return all possible permutations.
Example:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
Accepted 437,979 Submissions 761,542
二 分析
求全排列。medium 级别。从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
之前做过一个题目:leetcode 31. Next Permutation 就是求全排列的下一个字典序。
我们有知道全排列就是N! 个结果。所以直接套用:
public static List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums == null){
return res;
}
int count = 1;
for(int i=1;i<=nums.length ;i++){
count *=i;
}
while( count>0){
nextPermutation(nums);
List<Integer> l = new ArrayList<>();
for(int i=0;i<nums.length;i++){
l.add(nums[i]);
}
res.add(l);
count --;
}
return res;
}
这不是个好办法。还是回到题目本身上。
2.1 递归
- 数字1个本身就是全排序。
- 1跟2,就是12,21 两种
- 1、2、3 就是 [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 2, 1], [3, 1, 2] 即以1开头的和2、3的全排列的组合、以2开头的和1,3的全排列的组合和以3开头的和1,2的全排列的组合。
以次推理,1234全排列就是:
1 + 234(的全排列)
2 + 134(的全排列)
3 + 124(的全排列)
4 + 123 (的全排列)
可以理解,后面每个数都跟第一个交换过。总结来说就是采用位置两两交换,交换后出现一种新的组合,将这种新的组合添加到结果集。代码如下:
public static List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
helper(nums,0, res);
return res;
}
//递归
private static void helper( int[] nums, int start,List<List<Integer>> res ){
if(start == nums.length-1){//到达结尾,实现全排序
ArrayList<Integer> list = new ArrayList<>();
for(int num: nums){
list.add(num);
}
res.add(list);
return;
}
// 将当前位置的数跟后面的数交换,并搜索解
for(int i=start;i< nums.length;i++){
swap(nums,i,start);//交换
helper(nums,start+1 ,res);
swap(nums,i,start);//还原
}
}
private static void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
Runtime: 1 ms, faster than 97.68% of Java online submissions forPermutations.
Memory Usage: 37.8 MB, less than 89.36% of Java online submissions forPermutations.
时间复杂度:O(N!)
还有种递归的实现方式,grandyang大神说是CareerCup 书上的,网上也有这种介绍。又学习一个点。
这种思路是采用逐一向临时list添加元素,临时list满足条件后再加入到结果res中。
当 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, a2a1a
这样看起来,也是很好理解的。更简洁些
public static List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
ArrayList<Integer> list = new ArrayList<>();
helper(nums,list, res);
return res;
}
//递归2 插入法
private static void helper( int[] nums, ArrayList<Integer> list, List<List<Integer>> res ){
if(list.size() == nums.length){//到达结尾,实现全排序
res.add(new ArrayList<>(list));
return;
}
for(int i=0;i<nums.length;i++){
//插入前先判断
if(!list.contains(nums[i]) ){
list.add(nums[i]);//插入
helper(nums,list,res);
list.remove(list.size()-1);//删除
}
}
}
Runtime: 1 ms, faster than 97.68% of Java online submissions forPermutations.
Memory Usage: 37.1 MB, less than 97.16% of Java online submissions forPermutations.
参考:
https://www.cnblogs.com/grandyang/p/4358848.html