算法DAY28 | 【LeetCode力扣】78.子集 / 90.子集II

文章介绍了两个使用递归和回溯算法解决子集问题的Java实现。78.子集问题无需剪枝,遍历所有可能的子集。90.子集II在原问题基础上增加了去重逻辑,避免生成重复的子集路径,通过标记数组used来处理重复元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

78.子集

  • 标签:递归、回溯
  • 难度:7.5

求取子集问题,不需要任何剪枝!因为子集就是要遍历整棵树,不像组合问题只需要收集叶子结点。

递归参数要加上startIndex,因为取过的元素不能再取了。

递归终止条件就是startIndex大于数组的长度,剩余集合就为空了。
在这里插入图片描述

List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();

public List<List<Integer>> subsets(int[] nums) {
    backtracking(nums,0);
    return res;
}

public void backtracking(int[] nums, int startIndex){
    res.add(new ArrayList<>(path));

    if(startIndex >= nums.length){
        return;
    }

    for(int i = startIndex; i < nums.length; i++){
        path.add(nums[i]);
        backtracking(nums,i+1);
        path.remove(path.size() - 1);
    }
}

90.子集II

  • 标签:递归、回溯
  • 难度:8.0

这道题在上一道的基础上加了去重的逻辑。

本题允许在某个path里有重复元素,但不允许出现重复的path,这就是允许“树枝重复”,但不允许同一“树层重复”

用一个和nums等长的used数组,标记前一个元素是否加进path里。如果遍历到nums里的第i个元素,发现和第i-1个元素相等,且:

  • used[i]==1,说明前一个元素是在同一个树枝里,那没事,可以重复。
  • used[i]==0,说明前一个元素是在同一个树层里,那不行,直接continue。

为什么used[i]==0就一定在同一个树层里呢?根据下面的图,同一树层左边的元素一开始确实被加进了path里,used[i]也被置为1了,但是在回溯的过程中被恢复为了0。
在这里插入图片描述

所以回溯的时候一定记得,不仅path数组的最后一个元素要弹出,used数组的对应元素也要恢复。

注意:子集问题一定要排序。

List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
boolean[] used;

public List<List<Integer>> subsetsWithDup(int[] nums) {
    Arrays.sort(nums);
    used = new boolean[nums.length];
    backTracking(nums, 0);
    return res;
}

public void backTracking(int[] nums, int startIndex){
    res.add(new ArrayList<>(path));

    if(startIndex >= nums.length){
        return;
    }

    for(int i = startIndex; i < nums.length; i++){
        if(i>0 && nums[i] == nums[i-1] && !used[i-1]){
            continue;
        }

        path.add(nums[i]);
        used[i] = true;
        backTracking(nums, i+1);
        path.remove(path.size() - 1);
        used[i] = false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值