本次题目
46 全排列
- 回溯:对比之前的组合问题(组合,分割,子集),排列问题是有序的,因此不用定义startIndex。
- 需要定义一个used数组,标记已经选择过的元素;
- 当排列元素个数等于给定数组个数时终止;
- 通过used数组记录使用过的元素,在一个排列中(树根)一个元素只能使用一次。
class Solution {
//定义全局数组存放排列子集,定义全局二维数组存放子集集合
LinkedList<Integer> res = new LinkedList<>();
List<List<Integer>> result = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
//定义一个used数组,标记已经选择过的元素
boolean[] used = new boolean[nums.length];
//开始回溯
backtracking(nums, used);
//返回结果
return result;
}
//回溯函数
private void backtracking(int[] nums, boolean[] used){
//当排列元素个数等于给定数组个数时终止
if(res.size() == nums.length){
result.add(new LinkedList<>(res));
return;
}
for(int i = 0; i < nums.length; i++){
//通过used数组记录使用过的元素,在一个排列中(树根)一个元素只能使用一次
if(used[i] == true) continue;
res.add(nums[i]);
used[i] = true;
//回溯
backtracking(nums, used);
res.removeLast();
used[i] = false;
}
}
}
全排列II
- 回溯:对比上面 46 全排列,本题给定数组中元素可重复,排列需要不重复,同之前组合和子集中的去重,需要先对给定数组排序,然后通过for循环去重(不为第一个元素,当前元素和上一个元素是否相等,且上一个元素的used数组为false)。若为false说明同一数层中使用过;若为true则说明同一树根上使用过)。
- 注意:可以将used数组定义为全局变量。
class Solution {
//定义全局数组存放排列子集,定义全局二维数组存放子集集合
LinkedList<Integer> res = new LinkedList<>();
List<List<Integer>> result = new LinkedList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
//定义一个used数组,标记已经选择过的元素
boolean[] used = new boolean[nums.length];
//先对给定数组排序
Arrays.sort(nums);
//开始回溯
backtracking(nums, used);
//返回结果
return result;
}
//回溯函数
private void backtracking(int[] nums, boolean[] used){
//当排列元素个数等于给定数组个数时终止
if(res.size() == nums.length){
result.add(new LinkedList<>(res));
return;
}
//通过for循环判断当前元素和上一个元素是否相等,若相等则跳过
for(int i = 0; i < nums.length; i++){
if(i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue;
//通过used数组记录使用过的元素,在一个排列中(树根)一个元素只能使用一次
if(used[i] == true) continue;
res.add(nums[i]);
used[i] = true;
//回溯
backtracking(nums, used);
res.removeLast();
used[i] = false;
}
}
}