题目:
给定一个不含重复数字的整数数组 nums ,返回其 所有可能的全排列 。可以 按任意顺序 返回答案。
1.输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
2.输入:nums = [0,1]
输出:[[0,1],[1,0]]
3.输入:nums = [1]
输出:[[1]]
分析:
排列不同于组合,排列和元素的顺序相关,交换数字能够得到不同的排列。生成全排列的过程就是交换输入集合中元素的顺序以得到不同的排列。
该题思路是如果输入的集合与n的元素,那么生成一个全排列需要n步,当生成排列的第1个数字时会面临n个选项,即n个数字都有可能成为排列的第1个数字,生成排列的第1个数字之后接下来生成第2个数字,此时面临n-1个选项,也就是剩下的n-1个数字都有可能成为第2个数字…以此类推,直到生成最后一个数字,此时只剩下1个数字,也就只有1个选项。看起来有n步,实则每一步都面临若干个选项。
下图是排列123的例子:
具体操作看代码
假设数组nums的长度为n,当i等于0时递归函数helper中的for循环执行了n次,当i等于1的时候for循环等于n-1次,以此类推当i=n-1时,for循环执行1次,因此全排列的时间复杂度为O(n!)。
代码:
import java.util.LinkedList;
import java.util.List;
public class Permute {
public static void main(String[] args) {
Permute permute = new Permute();
int[] nums = {1,2,3};
List<List<Integer>> permute1 = permute.permute(nums);
System.out.println(permute1);
}
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new LinkedList<>();
helper(nums,0,result);
return result;
}
//在函数执行中,数组nums保存着当前排列的状态
private void helper(int[] nums, int i, List<List<Integer>> result) {
if (i == nums.length){
LinkedList<Integer> permutation = new LinkedList<>();
for (Integer num : nums) {
permutation.add(num);
}
result.add(permutation);
}else{
//i,j最外层的for循环0,0 0,1 0,2
for (int j = i; j < nums.length; j++) {
swap(nums,i,j);
// 当函数helper生成的排列的下标为i的数字时,下标从0到i-1的数字都已经被选定
helper(nums,i+1,result);
// 由于之前已经交换了数组中的两个数字,修改了排列的状态,在函数退出之前需要清除对排列状态的修改,因此交换之前交换的两个数字
swap(nums,i,j);
}
}
}
private void swap(int[] nums,int i,int j){
if (i!=j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}