题目链接:
https://leetcode-cn.com/problems/permutations-ii/
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 :
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
这道题只是46.全排列(https://leetcode-cn.com/problems/permutations/submissions/)的改版而已,实现思路大致相同,只是去重发生了一些变化,这道题要对树层进行去重。先抽象成树结构方便理解:
同一层不能取到重复的元素,代码中使用used数组进行去重的
套用递归四部曲:
递归作用:从nums找出所有排列
递归参数:nums意义同题意
终止条件:path.size() == nums.length
单层逻辑:这一层从所有为0开始取,并设置去重条件,取完这层再从0开始取下一层
回溯算法在操作完这一层后要初始化状态量进行回溯
代码如下:
class Solution {
List<List<Integer>> result = null;
List<Integer> path = null;
boolean[] used = null;//对树层去重用的,同时保证不会再取到已经取过的数据本身(这里指的是数据本身而不是重复的数据)
void permute1(int[] nums){
//递归作用:从nums找出所有排列
//递归参数:nums意义同题意
//终止条件:path.size() == nums.length
//单层逻辑:这一层从所有为0开始取,并设置去重条件,取完这层再从0开始取下一层
if(path.size() == nums.length){
result.add(new ArrayList(path));
return;
}
for(int i = 0; i < nums.length; i++){//从所有为0开始取,并设置去重条件,取完这层再从0开始取下一层
if((i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) || used[i] == true) continue;//这个数在这一树层被取了或者这个数之前已经被取过了(这里指的是数据本身而不是重复的数据)这里的第二个作用和46.全排列的used一样
path.add(nums[i]);
used[i] = true;
permute1(nums);
used[i] = false;
path.remove(path.size() - 1);//回溯
}
}
public List<List<Integer>> permuteUnique(int[] nums) {
result = new ArrayList<>();
path = new ArrayList<>();
used = new boolean[nums.length];
Arrays.sort(nums);
permute1(nums);
return result;
}
}