全排列

174 阅读2分钟

这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

leetcode 全排列

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

解题:

这个相当于密码锁上有几个数字,让你猜这个密码有可能是什么,但是这些数组每个组合只能使用一次,那么可以看成这些组合都是待填的空格,你只需把这些数组按不同的排列组合依次填上去即可。那么这就是一种穷举的算法了,我们从左到右依次将数字填入,最后填完数字就是一种组合,当然这些组合不能重复存在。具体的可以利用递归来实现,可以将给定的数组分成两个部分,一部分表示为填过使用了的数字,一部分表示还未使用待填的数字,然后递归的时候动态维护这个数组就行。 假如我们填到了first这个位置,那么数组中first的前面部分是已经填过了的,first后面的就是待填的数,然后就是用first后面的数字去填first位置的数了,那么填过去这个数后,我们就将这个数和第first个数交换,使得再填first的下一个数的时候,数组的first前的数是填过了的,first+1后的数是待填的,然后回溯的时候只需要交换回来就可以回到上一步了。例如[2, 5, 8, 9, 10],需要填入第三个数了,已经填了[2, 5]两个数,那目前的数组就是[2, 5 | 8, 9, 10],|分隔符是区分两个部分的, 假如下一个位置是要填的是10,那么可以将2和10交换,变为[2, 5, 10 | 9, 8],使得数组保持分隔,左边的数已经填完,右边的数是待填的。

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();

        List<Integer> output = new ArrayList<Integer>();
        for (int num : nums) {
            output.add(num);
        }
        int n = nums.length;
        backtrack(n, output, res, 0);
        return res;
    }

    public void backtrack(int n, List<Integer> output, List<List<Integer>> res, int first) {
        if (first == n) {
            res.add(new ArrayList<Integer>(output));
        }
        for (int i = first; i < n; i++) {
            Collections.swap(output, first, i);
            backtrack(n, output, res, first + 1);
            Collections.swap(output, first, i);
        }
    }
}