一.当全排列没有重复数字时:
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
思路:
- 看到排列问题,首先想到回溯算法,此题解题思路如下:
说明: - 对每一次遍历的数,我们需要给它设置一个状态变量used,方便判断其是否使用过;
- 使用深度优先遍历有「回头」的过程,在「回头」以后, 状态变量需要设置成为和先前一样(false),因此在回到上一层结点的过程中,需要撤销上一次的选择,这个操作称之为「状态重置」;
- 深度优先遍历,借助系统栈空间,保存所需要的状态变量,在编码中只需要注意遍历到相应的结点的时候,状态变量的值是正确的,具体的做法是:往下走一层的时候,path变量在尾部追加,而往回走的时候,需要撤销上一次的选择,也是在尾部操作,因此 path 变量是一个栈;
- 深度优先遍历通过「回溯」操作,实现了全局使用一份状态变量的效果。
代码如下:
* @Auther: qiuzelin
* @Date: 2020/12/09/10:09
* @Description:全排列
*/
public class Permutation {
public List<List<Integer>> permute(int[] nums) {
int n = nums.length;
List<List<Integer>> res = new ArrayList<>();
if (n == 0) {
return res;
}
Deque<Integer> path = new ArrayDeque<>();
boolean[] used = new boolean[n];
dfs(0, nums, path, n, res, used);
return res;
}
private void dfs(int depth, int[] nums, Deque<Integer> path, int n, List<List<Integer>> res, boolean[] used) {
//判断终止条件
if (depth == n) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < n; i++) {
if (used[i]) {
continue;
}
path.addLast(nums[i]);
used[i] = true;
dfs(depth + 1, nums, path, n, res, used);
path.removeLast();
used[i] = false;
}
}
}
二.当全排列有重复数字时:
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
思路:
要解决重复问题,我们只要设定一个规则,保证在填第i个数的时候重复数字只会被填入一次即可,其余思路与上题一致,在本题解中:
- 我们选择对原数组排序,保证相同的数字都相邻
Arrays.sort(nums);
- 然后每次填入的数一定是这个数所在重复数集合中「从左往右第一个未被填过的数字」:
if (used[i]||i>0&&nums[i]==nums[i-1]&&used[i-1]==false){
continue;
}
代码如下:
* @Auther: qiuzelin
* @Date: 2020/12/14/20:11
* @Description: 全排列II
*/
public class PermutationII {
public List<List<Integer>> permuteUnique(int[] nums) {
int n=nums.length;
List<List<Integer>> res=new ArrayList<>();
if (n==0){
return res;
}
Arrays.sort(nums);
int depth=0;
Deque<Integer> path=new ArrayDeque<>();
boolean[] used=new boolean[n];
backTrack(res,0,path,used,nums,n);
return res;
}
private void backTrack(List<List<Integer>> res,int depth,Deque<Integer> path,boolean[] used,int[] nums,int n){
if (depth==n){
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < n; i++) {
if (used[i]||i>0&&nums[i]==nums[i-1]&&used[i-1]==false){
continue;
}
path.addLast(nums[i]);
used[i]=true;
backTrack(res,depth+1,path,used,nums,n);
path.removeLast();
used[i]=false;
}
}
}