//收集从num数组n个数里面选N个数的组合
class Solution {
static int[] nums = {1, 2 ,3,4,5};
static int[] nums = {1, 2 ,2,4};
static ArrayList<Integer> path = new ArrayList<>();
public static boolean[] used = new boolean[nums.length];
public static final int N = 3;
public static void main(String[] args) {
List<ArrayList<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
//有重复数字的时候需要进行这一步操作,使相同数字挨在一起。
backtrack(0, res);
System.out.println("reslen"+ res.size());
for (ArrayList<Integer> re : res) {
System.out.println(re);
}
}
private static void backtrack(int start, List<ArrayList<Integer>> res) {
if(path.size() == N ){
res.add(new ArrayList<>(path));
return;
}
for (int i = start; i < nums.length ; i++) {
//i从start开始一般不需要used辅助数组。从0开始一般需要,意味着全排列。
//if( i>0 && nums[i] == nums[i - 1])continue; 有重复数字的时候
path.add(nums[i]);
backtrack(i + 1, res);//这里i加不加1取决于当前这个数字能不能被重复使用。
// 组合问题 backtrack(i+ 1,res);
//这种时候就只能用: if(path.size() == N){这个递归条件
path.remove(path.size()-1);
}
}
}
//以下全是没有重复元素的全排列。含有n个元素的数组选N个元素的全排列。
private static void backtrack(int idx, List<ArrayList<Integer>> res) {
/* if(idx == N ){
res.add(new ArrayList<>(path));
return;}*/
if(path.size() == N){
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length ; i++) {
//排列问题从0开始遍历,1,3,2和1,2,3算不同的。
if(!used[i]) {
used[i] = true;
path.add(nums[i]);
backtrack(idx+ 1,res);
// 传递单独的idx变量的时候,开头那两种递归终止条件都可以用。
// 也可以 backtrack(i+ 1,res);
//这种时候就只能用: if(path.size() == N){这个递归条件
path.remove(path.size() - 1);
used[i] = false;
}}}}
//全排列也可以直接不用传递归下标。
private static void backtrack( List<ArrayList<Integer>> res) {
if(path.size() == N){
//改成 if(path.size() == nums.length){即是直接收集求一个数组的全排列
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length ; i++) {
if(!used[i]) {
used[i] = true;
path.add(nums[i]);
backtrack(res);
path.remove(path.size() - 1);
used[i] = false;
}}}}
//有重复数字。
private static void backtrack( List<ArrayList<Integer>> res) {
if(path.size() == N){
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length ; i++) {
if(used[i] || (i > 0 && nums[i] == nums[i-1] && !used[i-1]))continue;
//n个里面选r个,只能用这个同层剪切去重,并且效率最高。
// if(used[i] || (i > 0 && nums[i] == nums[i-1] && used[i-1]))continue;
//全排列n个里面选n个,这个排重也是可以的。同枝剪切,但是效率相比要低些。
used[i] = true;
path.add(nums[i]);
backtrack(res);
path.remove(path.size() - 1);
used[i] = false;
}}}