0
点赞
收藏
分享

微信扫一扫

LC46-全排列----LC47-全排列 II


​​46. 全排列​​

文章目录

  • ​​[46. 全排列](https://leetcode-cn.com/problems/permutations/)​​
  • ​​[47. 全排列 II](https://leetcode-cn.com/problems/permutations-ii/)​​


难度中等1089

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

回溯法:

以数组 [1, 2, 3] 的全排列为例。

先写以 11 开头的全排列,它们是:[1, 2, 3], [1, 3, 2],即 1 + [2, 3] 的全排列(注意:递归结构体现在这里);
再写以 22 开头的全排列,它们是:[2, 1, 3], [2, 3, 1],即 2 + [1, 3] 的全排列;
最后写以 33 开头的全排列,它们是:[3, 1, 2], [3, 2, 1],即 3 + [1, 2] 的全排列。

递归的终止条件是: 一个排列中的数字已经选够了

状态变量:

  • 递归到第几层 depth​​Deque<Integer> path = new ArrayDeque<Integer>();​
  • 已经选了哪些数 path
  • 布尔数组 use 初始化的时候都为 false 表示这些数还没有被选择,当我们选定一个数的时候,就将这个数组的相应位置设置为 true ,这样在考虑下一个位置的时候,就能够以 O(1)O(1) 的时间复杂度判断这个数是否被选择过,这是一种「以空间换时间」的思想。
    ​​​详解请看文字描述​​​​官方视频解析​​

package com.nie.OneJanLC;/*
*
*@auth wenzhao
*@date 2021/1/16 23:58
*/

import java.util.*;

public class LEE046L {
class Solution {
public List<List<Integer>> permute(int[] nums) {
int len = nums.length;
if (len == 0) {
return null;
}
List<List<Integer>> res = new ArrayList<>();
boolean[] use = new boolean[len];
Deque<Integer> path = new ArrayDeque<Integer>();
dfs(nums, len, 0, use, path, res);
return res;
}

private void dfs(int[] nums, int len, int depth, boolean[] use, Deque<Integer> path, List<List<Integer>> res) {
if (depth == len) {
res.add(new ArrayList<>(path));
return;
}
// 在非叶子结点处,产生不同的分支,这一操作的语义是:
// 在还未选择的数中依次选择一个元素作为下一个位置的元素,这显然得通过一个循环实现。
for (int i = 0; i < len; i++) {
if (use[i]) {
continue;
}
path.add(nums[i]);
use[i] = true;
dfs(nums, len, depth + 1, use, path, res);
// 注意:下面这两行代码发生 「回溯」,回溯发生在从 深层结点 回到 浅层结点 的过程,
// 代码在形式上和递归之前是对称的
use[i] = false;
path.removeLast();
}
}
}

}

​​47. 全排列 II​​

难度中等566

给定一个可包含重复数字的序列 ​​nums​​ ,按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]

示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

​​详解​​

在回溯处理前:必须先进行排序

LC46-全排列----LC47-全排列 II_java

  • 在图中 ② 处,搜索的数也和上一次一样,但是上一次的 1 还在使用中;
  • 在图中 ① 处,搜索的数也和上一次一样,但是上一次的 1 刚刚被撤销,正是因为刚被撤销,下面的搜索中还会使用到,因此会产生重复,剪掉的就应该是这样的分支。

在回溯处理前:必须先进行排序

所以在46题上基础上加上:

if (i > 0 && nums[i] == nums[i - 1] && used[i - 1]!=flase) {
continue;
}

package com.nie.OneJanLC;/*
*
*@auth wenzhao
*@date 2021/1/16 23:58
*/

import java.util.*;

public class LEE047L {
class Solution {
public List<List<Integer>> permute(int[] nums) {
int len = nums.length;
if (len == 0) {
return null;
}
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
boolean[] use = new boolean[len];
Deque<Integer> path = new ArrayDeque<>();
dfs(nums, len, 0, use, path, res);
return res;
}

private void dfs(int[] nums, int len, int depth, boolean[] use, Deque<Integer> path, List<List<Integer>> res) {
if (depth == len) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; i++) {
if (i > 0 && use[i] == use[i - 1] && use[i - 1] != false) {
continue;
}
if (use[i]) {
continue;
}
path.add(nums[i]);
use[i] = true;
dfs(nums, len, depth + 1, use, path, res);
use[i] = false;
path.removeLast();
}
}
}

}


举报

相关推荐

0 条评论