全排列
题目:46
- 排列,讲究一个顺序的不同。相同的几个数,顺序不同还是不一样的排列
- 所以这里和此前的找不同组合不同,不需要startIndex来去重
- 这里就是只能用到used[i]了,只要保证当前正在选择的数不再被用就行了......吧
- 结束条件:单个集合长度和数组长度一样,毕竟是全排列啦。这里仍然可以把它当作二叉树,到达叶子节点即可。
- 因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。
而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次。
- 这里的used[]就是索引上的是否被使用,如果这个path(单个答案集合)里已经用过了这个数,就跳过
for (int i = 0; i < nums.length; i++){
if (used[i]){
continue;
}
- 排列问题与之前的不同:
- 每层都是从0开始搜索而不是startIndex
- 需要used数组记录path里都放了哪些元素了
- 或许,把used数组当作全局变量,是看这个树在深度上有没有被重复用的数字,就是这个全排列。在一个方法里,就是代表当前层(例如上一题那个递增子序列
全排列II
题目:47
- 引入重复数字,找没有重复的排序组合
- 那么就是在排列问题的基础上引入常规的去重操作,先给数组排序再用used[i]的那种,毕竟全排序里没有startIndex
if (i > 0 && !used[i - 1] && nums[i - 1] == nums[i]) {
continue;
}
- 如果要对树层中前一位去重,就用
used[i - 1] == false,毕竟,额,都到了nums[i]了,说明nums[i-1]应该已经被回溯过/用过了,已经是false了......吧? - 如果要对树枝前一位去重用
used[i - 1] == true不过推荐用对数层前一位去重 - 同时不要忘记,只有发现这个元素没在path里用过的时候,才能进行递归到下一层然后回溯哦
if (used[i] == false) {
path.add(nums[i]);
used[i] = true;
backTracking(nums,used);
path.remove(path.size() - 1);
used[i] = false;
}
一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。