46. 给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,1,2] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
class Solution {
public List<List<Integer>> permute(int[] nums) {
if (nums == null || nums.length == 0) return null;
List<List<Integer>> res = new ArrayList<>();
List<Integer> track = new ArrayList<>();
helper(nums,res,track);
return res;
}
private void helper(int[] nums,List<List<Integer>> res,List<Integer> track) {
if (track.size() == nums.length) {
res.add(new ArrayList<>(track));
}
for(int i = 0; i < nums.length; i++) {
if (!track.contains(nums[i])) {
track.add(nums[i]);
helper(nums,res,track);
track.remove(track.size()-1);
}
}
}
}
47. 给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2] 输出: [ [1,1,2], [1,2,1], [2,1,1] ]
关于重复问题,很有用的一种方法是现将数组排序!!!
Arrays.sort(arr);
class Solution {
// 参考代码
// public List<List<Integer>> permuteUnique(int[] nums) {
// List<List<Integer>> res = new ArrayList<>();
// Arrays.sort(nums);
// int[] visited = new int[nums.length];
// backtrack(res, nums, visited, new ArrayList<Integer>());
// return res;
// }
// private void backtrack(List<List<Integer>> res, int[] nums, int[] visited, ArrayList<Integer> tmp) {
// if (tmp.size() == nums.length) {
// res.add(new ArrayList<>(tmp));
// return;
// }
// for (int i = 0; i < nums.length; i++) {
// if (visited[i] == 1 || (i > 0 && visited[i - 1] == 0 && nums[i - 1] == nums[i])) continue;
// visited[i] = 1;
// tmp.add(nums[i]);
// backtrack(res, nums, visited, tmp);
// tmp.remove(tmp.size() - 1);
// visited[i] = 0;
// }
// }
public List<List<Integer>> permuteUnique(int[] nums) {
if (nums == null || nums.length == 0) return null;
List<List<Integer>> res = new ArrayList<>();
List<Integer> track = new ArrayList<>();
Arrays.sort(nums);
boolean[] flag = new boolean[nums.length];
helper(nums,res,track,flag);
return res;
}
private void helper(int[] nums,List<List<Integer>> res,List<Integer> track,boolean[] flag) {
if (track.size() == nums.length) {
res.add(new ArrayList<>(track));
return;
}
for(int i = 0; i < nums.length; i++) {
// 边界判断语句,当i-1访问过,且i == i-1 时,跳过该次循环。
// 解释为 1 1 2以a1 a2 c说明,其中a1 == a2
// a1 a2 c
// 选a1 备选 a2 c,此时a2 c 均为未访问过
// 选a2 备选 a1 c,此时 a1 未被访问过
// 如果不进行剪枝的话,两种情况排列出来是有重叠的
// 因此,进行 flag[i-1]==false && nums[i] == nums[i-1]) 判断,将后一种情况减去。
if (flag[i] == true || (i >0 && flag[i-1]==false && nums[i] == nums[i-1])) continue;
flag[i] = true;
track.add(nums[i]);
helper(nums,res,track,flag);
flag[i] = false;
track.remove(track.size()-1);
}
}
}