LeetCode 46. 全排列

143 阅读2分钟

一、题目

给定一个不含重复数字的数组 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;
        }
    }
}

qrcode2.png