题目: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;
}
}
}
标签:used,递归,nums,list,HOT,数组,回溯,100,LeetCode
From: https://www.cnblogs.com/yuhang-wiki/p/16983954.html