codeTop100题(18)46. 全排列

91 阅读1分钟

1. 题目

46. 全排列

2. 分析

题目要求我们给出所有的排列方式,首先我们知道,如果是排列的那话,那么我们每一个数字都只能使用一次,如图的三个数字:

image.png

  1. 首先我们拿出1,剩下 2 和 3

image.png

1.1 再接着找下一个没用到的数组,就是2:

image.png

1.1.1 此时,排列只有两个,我们继续找到下一个3,这样子我们就得到了第一个组合1,2,3

image.png

1.2 拿到1之后,我们不拿2了,而是拿3

image.png

1.2.1 然后我们再拿一个2,就得到了第二个组合1,3,2 image.png

2.1 这次我们第一个不拿1,而是拿2,以此类推,我们最终拿到的组合如下:

[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

我们上面的过程,可以用递归+回溯进行实现:

  • 每一次递归都找一个没使用过的数字,数量够了结束递归。
  • 每次选中的数字,我们将他标记为已使用后进行递归,递归结束之后重新标记为未使用。

3. 代码

public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> lists = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    int[] used = new int[nums.length];
    permuteSub(nums, lists, list, used, 0);
    return lists;
}

public void permuteSub(int[] nums, List<List<Integer>> lists, List<Integer> list, int[] used, int c) {
    //排列数量够了,结束递归
    if (c == nums.length) {
        //注意这个要new 一个list
        lists.add(new ArrayList<>(list));
        return;
    }
    for (int i = 0; i < nums.length; i++) {
        if (used[i] == 0) {
            used[i] = 1;
            list.add(nums[i]);
            permuteSub(nums, lists, list, used, c+1);
            //通过remove,递归过程中使用同一个list,减少空间消耗
            list.remove(list.size() - 1);
            used[i] = 0;
        }
    }
}