子集问题概述
78. 子集
求子集问题和77.组合 (opens new window)和131.分割回文串 (opens new window)又不一样了。
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!
其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。
那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!
可以不写递归终止条件,因为要遍历整个树
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> subsets(int[] nums) {backtrack(nums, 0);return res;}public void backtrack(int[] nums, int startIndex){res.add(new ArrayList<>(path));if (path.size() == nums.length) {return ;}for (int i = startIndex; i < nums.length; ++i) {path.add(nums[i]);backtrack(nums, i + 1);path.remove(path.size() - 1);}}}
90. 子集 II
「可能包含重复元素」startIndex + used[]
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> subsetsWithDup(int[] nums){Arrays.sort(nums);backtrack(nums, 0, new boolean[nums.length]);return res;}public void backtrack(int[] nums, int startIndex, boolean[] used){res.add(new ArrayList<>(path));if (path.size() == nums.length) {return ;}for (int i = startIndex; i < nums.length; ++i) {if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {continue;}path.add(nums[i]);used[i] = true;backtrack(nums, i + 1, used);used[i] = false;path.remove(path.size() - 1);}}}
491. 递增子序列
有重复元素,但是不能排序,不然就破坏了原来的递增关系,因此不能使用boolean uesd[]来去重,我们使用数组哈希,来判断这个数在当前层是否使用过。如果元素数值范围巨大,则使用HashMap代替数组哈希
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums){backtrack(nums, 0);return res;}public void backtrack(int[] nums, int startIndex){if (path.size() > 1) { //要求至少两个元素res.add(new ArrayList<>(path));}if (path.size() == nums.length) {return;}int[] used = new int[201];//因为元素范围是-100~100,共201个元素for (int i = startIndex; i < nums.length; ++i) {//不满足递增if (!path.isEmpty() && nums[i] < path.get(path.size() - 1)){continue;}//当前数字使用过了if(used[nums[i] + 100] == 1){continue;}used[nums[i] + 100] = 1;path.add(nums[i]);backtrack(nums, i + 1);path.remove(path.size() - 1);}}}
