今日算法之_49_全排列
前言
Github:https://github.com/HealerJean
1、全排列1
给定一个 没有重复 数字的序列,返回其所有可能的全排列
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
1.1、解题思路
回溯法
1.2、算法=>回溯法
1.2.1、去重判断1
/**
* 1、使用 集合本身判断是否重复
*/
public List<List<Integer>> permute2(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
huisu(nums, lists, new LinkedList<>());
return lists;
}
public void huisu(int[] nums, List<List<Integer>> list, LinkedList<Integer> array){
if (array.size() == nums.length){
list.add(new ArrayList<>(array));
return;
}
for (int i = 0 ; i < nums.length; i++){
//结果集中不能包含重复的
if (array.contains(nums[i])){
continue;
}
array.add(nums[i]);
huisu(nums, list, array);
//删除后一个节点,向上回溯
array.removeLast();
}
}
1.2.2、去重判断2
/**
* 2、开启一个新的数组判断是否重复
*/
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
boolean[] used = new boolean[nums.length];
huisu(nums,used, lists, new LinkedList<>());
return lists;
}
public void huisu(int[] nums,boolean[] used, List<List<Integer>> list, LinkedList<Integer> array){
if (array.size() == nums.length){
list.add(new ArrayList<>(array));
return;
}
for (int i = 0 ; i < nums.length; i++){
//结果集中不能包含吃不惯分页
// if (array.contains(nums[i])){
// continue;
// }
if (used[i] == true){
continue;
}
array.add(nums[i]);
used[i] = true ;
huisu(nums,used, list, array);
//删除后一个节点,向上回溯
used[i] = false ;
array.removeLast();
}
}
1.3、测试
@Test
public void test(){
int nums[] = {1,2,3,4};
System.out.println(permute(nums));
}
控制台:
[[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2], [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4, 1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], [4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]
1、全排列2
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
1.1、解题思路
同上,也是使用回溯法,我们唯一需要注意的地方就是去重 。层与层直接无需去重,如果是同一层,则需要去重
一定要排序,只有排序了,我们才能判断相邻的相等
1.2、算法
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
boolean[] used = new boolean[nums.length];
dfs(nums, used, new LinkedList<>(), list);
return list;
}
private void dfs(int[] nums, boolean[] used, LinkedList array, List<List<Integer>> list) {
if (array.size() == nums.length) {
list.add(new ArrayList<>(array));
return;
}
for (int i = 0; i < nums.length; ++i) {
//当前值用过了(从开始回溯,肯定会重复使用,所以要判断) 或
//当前值等于前一个值: 两种情况:(归根接地,就是要保证 同一层的时候,num[n-1] 如果不等于true了,continue)
//1 [i-1] = false,没有被使用, 说明回溯到了同一层 ,这个时候满足了 nums[i] == nums[i - 1],肯定是重复,所以continue
//2 [i-1] = true, 用过了 说明此时在num[i-1]的下一层,这种情况可以往下走,不需要continue
if (used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])) {
continue;
}
array.add(nums[i]);
used[i] = true;
dfs(nums, used, array, list);
// 回溯部分的代码,和 dfs 之前的代码是对称的
used[i] = false;
array.removeLast();
}
}
1.3、测试
@Test
public void test(){
int nums[] = {1,1,2};
//切记必须要先排序啊!!!!!!这样只有相邻的才可能相等,才可以判断去除!!!!!
Arrays.sort(nums);
System.out.println(permuteUnique(nums));
}
控制台:
[[1, 1, 2], [1, 2, 1], [2, 1, 1]]