LeetCode HOT 100:全排列

题目:46. 全排列

题目描述:

给你一个没有重复元素的数组,返回其所有可能的全排列。全排列是什么呢?举个简单的例子,数组[1, 2, 3],其中一个排列为[2, 1, 3],该数组所有的全排列为[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]

思路:

这道题是很典型的回溯。回溯其实就是穷举,最多加点剪枝优化一下。所以这题思想就很简单,把每个元素不断穷举,来组成新的排列。但是要记住一点,在一次排列中,一个元素只能使用一次。意思就是在一次递归中,要将已经使用过的元素标记出来,在本次递归中不能再使用了。

步骤:

本题主要是回溯方法怎么写,所以下面步骤是回溯方法的步骤。
1、先定义好回溯方法的入参
这一题入参也很简单,(原数组,标记是否已经使用的数组)
2、定义好回溯方法后,方法里首先确定递归结束的条件
这一题递归结束条件就是:临时数组添加的元素个数,等于原数组个数,说明该终止本次递归了
3、定义好终止条件,下面就是开始穷举,伪代码如下

for (int i = 0; i < nums.length; i++) {
	判断该下标的元素是否在本次递归中使用过了,如果没有,继续下面步骤
	将元素放入数组
	迭代回溯方法
	将元素从数组中删除,回溯
}

解释:

1、本题使用了回溯模版,可以解决很多类似问题,回溯模版在这里总结一下。

void process(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本次递归集合中元素(从开始下标到数组结尾)) {
        处理节点;
        process(参数); // 递归
        回溯,撤销处理结果
    }
}

代码:

    List<List<Integer>> ans;
    List<Integer> list;

    public List<List<Integer>> permute(int[] nums) {
        ans = new ArrayList<>();
        list = new ArrayList<>();

        // 用于标记 nums 中元素是否被使用过
        boolean[] used = new boolean[nums.length];
        process(nums, used);

        return ans;
    }

    public void process(int[] nums, boolean[] used) {
        // 集合大小等于数组长度,说明一个结果被找到了,可以结束本次递归了
        if (list.size() == nums.length) {
            ans.add(new ArrayList<>(list));
            return;
        }

        for (int i = 0; i < nums.length; i++) {
            // 如果该元素在本次递归没有被使用过
            if (!used[i]) {
                list.add(nums[i]);
                used[i] = true;
                process(nums, used);
                list.remove(list.size() - 1);
                used[i] = false;
            }
        }
    }
posted @ 2022-12-14 23:17  煜航  阅读(39)  评论(0编辑  收藏  举报