一、题目描述
给定一个不含重复数字的整数数组 nums ,返回其 所有可能的全排列 。可以 按任意顺序 返回答案。
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
二、代码思路
首先,我们直接能想到这是一个经典的回溯问题,也就是说针对每个元素逐步的判断,判断是否选取,从而形成整个的搜索树。回溯的思想已经很明确,如何实现?
最原始的回溯算法:
最原始的回溯,其实就是79题,所有子集:
public void dfs(int cur, int [] nums) {
if (cur == nums.length) {
ans.add(new ArrayList(t));
return;
}
t.add(nums[cur]);
dfs(cur + 1, nums);
t.remove(t.size() - 1);
dfs(cur + 1,nums);
}
也可以理解为二叉搜索树回溯算法,表现形式就是一颗二叉完全搜索树(不含剪纸操作)。
显然这种写法,是有劣势和优势的。
优势劣势如下表:
算法 | 优势 | 劣势 |
---|
回溯算法二叉树 79题 | 找所有子集 | 全排列不行 、不能重复选择元素 | 多叉搜素树 81题 | 可以重复选择元素 | n叉树效率低、重复选择元素 | 多叉搜索 + 判断 83题 | 可按照需求选元素(本题 全排列) | 没有明显劣势 | 数组存在重复元素 82题 | | 我们需要额外去重操作 |
多叉搜索树:
private void dfs(int[] nums, int cur) {
if (cur == nums.length) {
return;
}
for (int i = 0; i < nums.length; i++) {
sum += 1;
list.add(nums[i]);
dfs(nums, cur + 1);
sum -= 1;
list.remove(list.size() - 1);
}
}
多叉搜索树 + 判断:
private void dfs(int[] nums, int cur) {
if (sum == nums.length) {
res.add(new LinkedList(list));
return;
}
if (cur == nums.length) {
return;
}
for (int i = 0; i < nums.length; i++) {
if (flags[i] != 0) {
continue;
}
flags[i] = 1;
sum += 1;
list.add(nums[i]);
dfs(nums, cur + 1);
sum -= 1;
list.remove(list.size() - 1);
flags[i] = 0;
}
}
三、代码题解
分为三个版本的题解,每个版本进行逐步优化
3.1 多叉树 + set去重
package leetcode.lc20221020;
import java.util.*;
public class Solution01 {
private int sum;
private List<Integer> list = new LinkedList();
private List<List<Integer>> res = new ArrayList();
private Set<Integer> set = new HashSet();
public List<List<Integer>> permute(int[] nums) {
dfs(nums, 0);
return res;
}
private void dfs(int[] nums, int cur) {
if (sum == nums.length) {
res.add(new LinkedList(list));
return;
}
if (cur == nums.length) {
return;
}
for (int i = 0; i < nums.length; i++) {
if (set.contains(nums[i])) {
continue;
}
sum += 1;
set.add(nums[i]);
list.add(nums[i]);
dfs(nums, cur + 1);
sum -= 1;
list.remove(list.size() - 1);
set.remove(nums[i]);
}
}
}
3.2 多叉树 + 数组去重(空间复杂度较高)
private void dfs(int[] nums, int cur) {
if (sum == nums.length) {
res.add(new LinkedList(list));
return;
}
if (cur == nums.length) {
return;
}
for (int i = 0; i < nums.length; i++) {
if (flags[i] != 0) {
continue;
}
flags[i] = 1;
sum += 1;
list.add(nums[i]);
dfs(nums, cur + 1);
sum -= 1;
list.remove(list.size() - 1);
flags[i] = 0;
}
}
3.3 多叉树 + 选择 + 位运算去重(空间复杂度较低)
private void dfs(int[] nums, int cur) {
if (sum == nums.length) {
res.add(new LinkedList(list));
return;
}
if (cur == nums.length) {
return;
}
for (int i = 0; i < nums.length; i++) {
int temp = 1 << nums[i] + 10;
if ((flag & temp) != 0) {
continue;
}
sum += 1;
list.add(nums[i]);
flag = flag | temp;
dfs(nums, cur + 1);
sum -= 1;
list.remove(list.size() - 1);
flag = flag & (~temp);
}
}
|