代码随想录刷题day52|(回溯算法篇)78.子集(不去重)、90.子集 II(去重)

一、回溯算法理论知识

详见:代码随想录刷题day46|(回溯算法篇)77.组合-CSDN博客

二、子集问题思路

和组合问题不同的是:

子集中,收获结果是在每一个结点,而组合和分割问题,只在叶子结点/终止条件收获结果,子集中每进入一层递归,均将得到的结果放入结果集;

stratIndex:表示本层递归,for循环中从哪里开始取数;

终止条件:剩余集合为空,即stratIndex指向为空,表示到了叶子节点,本层递归终止;

放入结果集的位置:进入每一层递归,就要把当前结果放到结果集中,且应该放在终止条件的上面,因为子集问题并不是只在终止条件才收集结果;这一步确保了所有可能的子集都被记录下来,包括空集;

单层递归逻辑:for循环中,从startIndex指向位置开始遍历数组中元素,将当前元素加入到子集中,然后递归调用自身,处理下一个元素;递归返回后,回溯,将当前元素从子集中移除; 

子集去重:

去重思路同组合:代码随想录刷题day50|(回溯算法篇)40.组合总和 II-CSDN博客 

都是同一层去重;

注意两点:同层去重要对数组排序;去重逻辑是同一层中取过的元素不能再取;  

三、相关算法题目

78.子集

class Solution {
    List list = new ArrayList<>();//存放单个结果[1] [1,2]等
    List> result = new ArrayList<>();//存放所有结果
    public List> subsets(int[] nums) {
        backtracking(nums,0);
        return result;
    }
    private void backtracking(int[] nums, int startIndex){
        result.add(new ArrayList<>(list));
        if(startIndex >= nums.length){
            return;
        }
        for(int i = startIndex;i < nums.length;i++){
            list.add(nums[i]);
            backtracking(nums,i + 1);
            list.removeLast();//回溯
        }
    }
}

90.子集 II

去重

class Solution {
    List list = new ArrayList<>();//存放单个结果
    List> result = new ArrayList<>();//存放所有结果集
    public List> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);//对数组进行排序
        backtracking(nums,0);
        return result;
    }
    private void backtracking(int[] nums, int startIndex){
        result.add(new ArrayList<>(list));
        if(startIndex >= nums.length){
            return;
        }
        for(int i = startIndex;i < nums.length;i++){
            if(i > startIndex && nums[i] == nums[i - 1]){
                continue;
            }//同层去重
            list.add(nums[i]);
            backtracking(nums,i + 1);
            list.removeLast();
        }
    }
}

四、总结

1.子集问题收集最终结果的方式和位置 不同于组合和分割;

2.去重逻辑同组合,注意两点;

3.代码随想录用used数组去重的逻辑看不太明白,用了自己比较容易懂的逻辑; 

你可能感兴趣的:(我爱算法!我爱刷题!,算法)