从零学算法78

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

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = 1,2,3

输出:\[,1,2,1,2,3,1,3,2,3,1,2,3]

示例 2:

输入:nums = 0

输出:\[,0]

  • 如果将该题想象成一棵 n 叉树,进行 dfs,那么其实遍历时走过的每个路径都是子集。比如例子 1
复制代码
    		1
    	2		3
    3
  • 为了防止重复组合,所以在构建新的子集时,比如 1,3 我们继续构建时,不会往前取数字(取末尾的 3 前面的数字)构建成新的子集,比如得到 1,3,2,这也就是为什么上面那棵树是这样的。所以比如 1,2,3 ,我们得到 1,2,3 后不可能回溯成 1,3 然后得到 1,3,2,所以每次的下一层递归,从当前层递归的数组的下标 +1 开始,具体看代码
java 复制代码
  public List<List<Integer>> subsets(int[] nums) {
      List<List<Integer>> list = new ArrayList<>();
      backtrack(list, new ArrayList<>(), nums, 0);
      return list;
  }
  
  private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] nums, int start) {
      //走过的所有路径都是子集的一部分,所以都要加入到集合中
      list.add(new ArrayList<>(tempList));
      for (int i = start; i < nums.length; i++) {
          //做出选择
          tempList.add(nums[i]);
          //递归,i+1 防止重复结果
          backtrack(list, tempList, nums, i + 1);
          //撤销选择
          tempList.remove(tempList.size() - 1);
      }
  }
  • 位运算:其实在构建每个子集时都可以看成,每个数都有两种状态,加入子集或者不加入。设加入为 1,不加入为 0,数组长度为 n,就能把每个子集看做 n 位二进制数,那么总个数就是 2n。比如 1,2,3,每个子集都能看做三位的二进制数,\[\] 就是每个数都不选即 000,1,3 就对应 101。
  • 因此,比如例子 1,我们只需要遍历这 n(该例中为 8) 个数,范围为 0~7, 比如 6 对应为 110,就表示该子集为 2,3,再比如 3 对应为 011,表示子集 1,2(因为低位表示数组下标小的数)
java 复制代码
  public List<List<Integer>> subsets(int[] nums) {
      List<List<Integer>> res = new ArrayList<>();
      int len = nums.length;
      // 子集个数
      int resCount = 1<<len;
      // i 其实就是每种子集对应的二进制数的十进制
      for(int i=0;i<resCount;i++){
          List<Integer> list = new ArrayList<>();
          // 看是否包含 nums 中某个数
          for(int j=0;j<len;j++){
          	// 如果包含就添加到 list
              if((i>>j&1)==1)list.add(nums[j]);
          }
          res.add(list);
      }
      return res;
  }
  • 非递归:我们先加入一个空集,遍历时 nums 时每次都把 numsi 加到之前的子集中构建新子集,遍历完也就得到了全部子集。比如例子 1 我们会依次得到: []->[[],1]->[[],1,2,12]->[[],1,2,12,3,13,23,123]
java 复制代码
  public List<List<Integer>> subsets(int[] nums) {
      List<List<Integer>> res = new ArrayList<>();
      res.add(new ArrayList<>());
      for(int num : nums){
          int size = res.size();
          for(int j=0;j<size;j++){
              List<Integer> tempList = new ArrayList<>(res.get(j));
              tempList.add(num);
              res.add(tempList);
          }
      }
      return res;
  }
  • 强行递归也可以,其实就是递归形式的循环
java 复制代码
  public List<List<Integer>> subsets(int[] nums) {
      List<List<Integer>> res = new ArrayList<>();
      res.add(new ArrayList<>());
      dfs(nums,res,0);
      return res;
  }
  public void dfs(int[] nums,List<List<Integer>> res,int index){
      if(index >= nums.length)return;
      for(int i=0,j=res.size();i<j;i++){
          List<Integer> list = new ArrayList(res.get(i));
          list.add(nums[index]);
          res.add(list);
      }
      dfs(nums,res,index+1);
  }
  • 递归:还是上面的思路,我们在构建一种子集时,都可以看做对每个数选或不选。比如 nums:1,2,3 选择 12,不选 3,得到 011,也就是说完全可以当做一个二叉树,因为对于每个数只有选或不选两种可能,所以递归部分就写做选择的过程
java 复制代码
  public List<List<Integer>> subsets(int[] nums) {
      List<List<Integer>> res = new ArrayList<>();
      dfs(res, new ArrayList<>(), nums, 0);
      return res;
  }
  public void dfs(List<List<Integer>> res, List<Integer> list, int[] nums, int index){
      if(index == nums.length){
          res.add(new ArrayList<>(list));
          return;
      }
      // 不选,直接继续递归
      dfs(res, list, nums, index + 1);
      // 选择(加入 list)
      list.add(nums[index]);
      // 选完再递归
      dfs(res, list, nums, index + 1);
      // 撤销选择
      list.remove(list.size() - 1);
  }
相关推荐
tangguofeng30 分钟前
不带头结点的链队操作集(不含InitFlag)(C语言版)
算法
苏打豆2 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
蛋蛋的就会顺顺的2 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
老歌老听老掉牙2 小时前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
zhangfeng11333 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
学代码的CJY3 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录4 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
小O的算法实验室4 小时前
IEEE TEVC,基于精确与DQN群智能调度方法用于多目标异构USV
算法
可乐ea5 小时前
AI Agent 工具调用准确性评测:选择错误与参数错误分开测
大数据·人工智能·算法·大模型·工具调用·ai智能体·agent评测
上位机妹子5 小时前
C 语言 数组删除指定元素(快慢指针法)
c语言·数据结构·算法