回溯——子集

题目:
给你一个整数数组 nums ,数组中的元素 **互不相同 **。返回该数组所有可能的子集(幂集)。

这道题是求数组的幂集,核心思路是回溯算法(深度优先搜索),也可以用迭代法实现。因为数组元素互不相同,所以无需去重,直接生成所有子集即可。

方法一:回溯法
思路

  1. 子集的本质:每个元素都有不选两种选择,最终遍历所有组合。
  2. 回溯流程
  • 从数组第一个元素开始,依次决定是否加入当前子集。
  • 加入元素后递归处理下一个元素。
  • 递归返回后回溯(移除最后加入的元素),尝试不选该元素的情况。
  1. 每次递归都将当前子集加入结果集(空集也是子集)。

代码解释

  1. 全局变量:res存所有子集,path存当前正在构建的子集。
  2. 回溯函数
    res.add(new ArrayList<>(path)):必须新建列表,否则后续回溯会修改已加入的子集。
    for(int i = start; i<nums.length;i++):从当前start开始遍历,避免生成重复子集(如[1,2]和[2,1])。
    三步核心:选择->递归->回溯

完整代码实现如下:
class Solution {

//存储当前结果
List<List> res = new ArrayList<>();
//存储当前子集
List path = new ArrayList<>();

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

private void backtrack(int[] nums,int start){
//每次递归都将当前子集加入结果集(空集也会被加入)
res.add(new ArrayList<>(path));

//遍历从start开始的所有元素
for(int i = start;i<nums.length;i++){
//1. 选择:将当前元素加入子集
path.add(nums[i]);
//2. 递归:得到1的所有组合([1],[1,2],[1,2,3],[1,3])
baktrack(nums,i+1); //递归处理下一个元素,避免重复
//3. 回溯:移除每层递归最后加入的元素,元素2需要移除3和2两个元素
path.remove(path.size()-1);
}

}
}

回溯关键点解释:

元素3的for循环进入下一个元素的递归会先把当前子集加入res数组,由于i+1= nums.length,不会进入递归,返回到元素3的递归,进入回溯逻辑,把3移除。由于元素3已经到了是for循环的最后一个元素,移除3以后就直接返回到元素2的递归,把2移除,由于for循环并未遍历到末尾,执行i++,进入到元素3的for循环,将元素3加入path,,把[1,3]加入res,返回到3的递归(这里的3的递归实质是在2的递归中执行的3的递归)把3移除,再返回到元素1的递归,将元素1移除。至此把元素1的所有组合添加到res中,for循环遍历到第二个元素,开始添加2的组合子集。总结:每个for循环都是处理当前元素的所有组合,通过递归来添加下一个元素到当前元素的集合中,每层递归之前将当前子集加入res中,递归到底后回溯移除最后加入的元素。

本题默认数组中不存在重复元素,拿如果数组元素会重复呢?

如果题目改成:
给你一个整数数组 nums,数组中可能包含重复元素,返回所有可能的子集。
这时候必须去重,否则结果里会有大量重复子集。

去重核心规则

  1. 先排序(让重复元素挨在一起)
  2. 跳过重复元素:同一层、相同值、不是第一个选择 → 跳过
posted @ 2026-04-26 11:17  ZealousMclaren  阅读(16)  评论(0)    收藏  举报