lc78子集 回溯

lc.78 子集

    • 题目描述
    • 正解

题目描述

来源:leetcode_hot100_78
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]

错误示范
思路:每次添加的不能是path。由于 Java 中的集合是对象引用的集合,这意味着每次更改 path 时,添加到 list 中的所有实例也会受到影响。为了解决这个问题,需要确保每次都向 list 添加一个新的列表实例,而不是相同的引用。可以通过使用 new ArrayList<>(path) 创建 path 的副本来做到这一点。这样,每个子集都有自己独立的列表,不会受到其他子集修改的影响。

class Solution {
    
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list = new LinkedList<>();
        List<Integer> path = new LinkedList<>();
        backtrace(nums,0,list,path);
        return list;
    }

    public void backtrace(int[] nums, int startindex, List<List<Integer>> list,List<Integer> path){
        list.add(path);//这里错了
        if(startindex >= nums.length) return ;
        for(int i=startindex; i<nums.length;i++){
            path.add(nums[i]);
            backtrace(nums,i+1,list,path);//i+1而非startindex+1
            path.remove(path.size()-1);//相当于pop
        }
        return ;
    }
}

调用 backtrace 方法时,它首先将当前子集(即 path)加入到结果列表中。然后,通过 for 循环从当前索引 startindex 开始遍历数组元素。在每次迭代中,将当前元素(nums[i])添加到子集中,然后递归调用 backtrace。
关键点在于递归调用中的索引选择。通过使用 i+1 而不是 startindex+1,确保了在递归调用中从当前元素的下一个元素开始。这样做是为了避免生成重复的子集,因为每个元素在当前子集中只能出现一次。
在递归调用返回后,通过移除最后一个添加的元素,回溯到上一层状态,以便继续生成其他子集。这种回溯的过程最终构建了包含原始数组所有可能子集的列表。
如果使用 startindex+1 而不是 i+1,将导致在递归调用中始终从当前的 startindex + 1 开始,而不考虑内部循环中的 i。这样会导致生成的子集出现重复,因为每次都是从 startindex + 1 开始,而不是从当前的 i + 1。
具体来说,这将导致每个元素都被重复添加到子集中,因为递归调用没有在内部循环中的 i 上进行迭代。这样的实现将无法正确生成不重复的子集,并可能产生不符合预期的结果。

正解

思路:回溯 但结果不是全在叶子结点而在路径上收集

class Solution {
    
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> list = new LinkedList<>();
        List<Integer> path = new LinkedList<>();
        backtrace(nums,0,list,path);
        return list;
    }

    public void backtrace(int[] nums, int startindex, List<List<Integer>> list,List<Integer> path){
        list.add(new LinkedList<>(path));//创建副本的重要性
        if(startindex >= nums.length) return ;
        for(int i=startindex; i<nums.length;i++){
            path.add(nums[i]);
            backtrace(nums,i+1,list,path);//i+1而非startindex+1
            path.remove(path.size()-1);//相当于pop
        }
        return ;
    }
}

你可能感兴趣的:(我与力扣斗智斗勇,算法,leetcode,java)