一、题目
给定一个不含重复数字的数组 nums,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入: nums = [1,2,3]
输出: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
二、思路
- 对于nums=[1],它所有的全排列就是[[1]],全排列总数是1。
- 对于nums=[1,2],它所有的全排列就是[[2,1],[1,2]],全排列总数是2。
- 对于nums=[1,2,3],它所有的全排列就是[[3,2,1],[2,3,1],[2,1,3],[3,1,2],[1,3,2],[1,2,3]],全排列总数是6。
从中可以看出,全排列总数其实就是n!,n是指nums[]数组的前n个数。
另外,nums=[1,2]的全排列其实是根据nums=[1]的全排列来构建的,就是将数字2插入全排列 [[1]] 的各个位置形成的。将2插入1的左边,形成[2,1];将2插入1的右边形成[1,2];最终构建得到[[2,1],[1,2]]。
对于nums=[1,2,3]的全排列,道理同样如此,它的全排列也是由nums=[1,2]的全排列构建的。如[3,2,1]其实是将3插入[2,1]的左边,等等。
很明显,这些符合动态规划的最优子结构性质:问题的最优解由相关子问题的最优解组合而成。
所以我们采用动态规划来解决这个问题。
三、代码
class Solution {
public List<List<Integer>> permute(int[] nums) {
return permute1(nums,nums.length);
}
/**
* 给定一个不含重复数字的数组nums,一个n,
* 返回数组nums的前n项数的,所有可能的全排列
*/
public List<List<Integer>> permute1(int[] nums,int n){
if(n==1) {
List<Integer> temp=new ArrayList<>();
temp.add(nums[0]);
List<List<Integer>> ansList= new ArrayList<>();
ansList.add(temp);
return ansList;
}else {
List<List<Integer>> preList=permute1(nums,n-1);
List<List<Integer>> ansList=new ArrayList<>();
//f(n)的全排列可以由之前f(n-1)的全排列构建
//例如[1,2]有三个位置可以插入3,变成[3,1,2],[1,3,2][1,2,3]
for(int i=0;i<preList.size();i++) {
//在f(n-1)的第0~size位置都插入nums[n]
for(int j=0;j<=preList.get(i).size();j++) {
List<Integer> temp=new ArrayList<>();
temp.addAll(preList.get(i));
temp.add(j, nums[n-1]);
ansList.add(temp);
}
}
return ansList;
}
}
}