leetcode-全排列

155 阅读2分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

最近被工作上的一些事情搞得焦头烂额,也有段时间每继续每天做题了。持续做一件事情,每天都能坚持,特别难,中途放弃又特别容易。但是正是因为这样,坚持下来的成就感才足够大吧。往昔不可追,做好当下才最重要。种一棵树最好的时机是十年前,其次是现在。

题目

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

思路

先想象一下,如果这个题目给你,人工会怎么做。
大致应该是:先获取位数,然后每一位都嵌套一层for循环,循环数组中的每个数字,但是有个条件是,外层for循环当前正在使用的数字,在里层的for循环就不能再使用了。
其实里层for循环到外层for循环的过程,就是回溯的过程。每次最先改变的是最里层for循环的值,这是对上一次结果的最小改变,慢慢的,再开始走外层的for循环,就是每次只改变一点点,慢慢试探,但是这个过程要做到不重不漏。下图就是示例1按照这个步骤的过程:

46回溯.png 我们现在就是要用代码来实现这一个过程,但是上面的思路中,数字的个数就是for循环的个数,直接是没法写的,因为数组的长度是变化的,只能写一个for循环,然后递归调用,递归的次数就是for循环的次数,即数组的长度。

Java版本代码

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        List<Integer> item = new ArrayList<>();
        int len = nums.length;
        boolean[] used = new boolean[len];
        dfs46(result, item, nums, 0, used);
        return result;
    }

    private static void dfs46(List<List<Integer>> result, List<Integer> item, int[] nums, int depth, boolean[] used) {
        int len = nums.length;
        if (depth == len) {
            result.add(new ArrayList<>(item));
            return;
        }
        for (int i = 0; i < len; i++) {
            if (!used[i]) {
                item.add(nums[i]);
                used[i] = true;
                dfs46(result, item, nums, depth + 1, used);
                used[i] = false;
                item.remove(item.size() - 1);
            }
        }
    }
}