从零学算法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 开始,具体看代码
  •   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](因为低位表示数组下标小的数)
  •   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 时每次都把 nums[i] 加到之前的子集中构建新子集,遍历完也就得到了全部子集。比如例子 1 我们会依次得到: []->[[],1]->[[],1,2,12]->[[],1,2,12,3,13,23,123]
  •   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;
      }
    
  • 强行递归也可以,其实就是递归形式的循环
  •   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,也就是说完全可以当做一个二叉树,因为对于每个数只有选或不选两种可能,所以递归部分就写做选择的过程
  •   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);
      }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/341551.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分布式websocket即时通信(IM)系统保证消息可靠性【第八期】

b站上面本期视频版本&#xff0c;观看视频食用更佳&#xff01;点击即可跳转,找不到视频可以直接搜索我 目前叫 呆呆呆呆梦 目前已经写的文章有。并且有对应视频版本。 git项目地址 【IM即时通信系统&#xff08;企聊聊&#xff09;】点击可跳转 sprinboot单体项目升级成sprin…

#GPU|LLM|AIGC#集成显卡与独立显卡|显卡在深度学习中的选择与LLM GPU推荐

区别 核心区别&#xff1a;显存&#xff0c;也被称作帧缓存。独立显卡拥有独立显存&#xff0c;而集成显卡通常是没有的&#xff0c;需要占用部分主内存来达到缓存的目的 集成显卡&#xff1a; 是集成在主板上的&#xff0c;与主处理器共享系统内存。 一般会在很多轻便薄型的…

Linux 网络传输学习笔记

这篇是混合《Linux性能优化实战》以及 《Wireshark网络分析就这么简单》的一些关于Linux 网络的学习概念和知识点笔记 &#xff0c;主要记录网络传输流程以及对于TCP和UDP传输的一些影响因素 Linux 网络传输流程 借用一张倪朋飞先生的《Linux性能优化实战》课程中的图片 接收流…

第二证券:新手也能搞定!新股申购流程攻略

由于参加打新的获利概率较大&#xff0c;也就有许多投资者参加到新股申购中。那么&#xff0c;新股申购流程是怎样的&#xff1f;对此&#xff0c;本文将借助有关知识来展开讨论&#xff0c;为我们供给一个参阅思路。 投资者在参加网上打新时&#xff0c;应首要了解新股的申购日…

测试不拘一格——掌握Pytest插件pytest-random-order

在测试领域,测试用例的执行顺序往往是一个重要的考虑因素。Pytest插件 pytest-random-order 提供了一种有趣且灵活的方式,让你的测试用例能够以随机顺序执行。本文将深入介绍 pytest-random-order 插件的基本用法和实际案例,助你摆脱固定的测试顺序,让测试更具变化和全面性…

yolov5 opencv dnn部署自己的模型

yolov5 opencv dnn部署自己的模型 github开源代码地址使用github源码结合自己导出的onnx模型推理自己的视频推理条件c部署c 推理结果 github开源代码地址 yolov5官网还提供的dnn、tensorrt推理链接本人使用的opencv c github代码,代码作者非本人&#xff0c;也是上面作者推荐的…

【Electron】Electron是什么

1. Electron是什么 Electron是使用JavaScript、HTML和CSS构建跨平台&#xff08;Windows、MacOs、Linux&#xff09;的桌面应用。Electron其实就是一个可以展示网页内容的壳子&#xff0c;相当于一个独立的浏览器&#xff0c;可以提供给你一些接口&#xff0c;去调用系统的资源…

验证码短信API:企业级安全验证的必备工具

引言 随着数字经济的蓬勃发展&#xff0c;企业对在线服务的安全性要求越来越高。在这种背景下&#xff0c;验证码短信API作为一种有效的安全验证工具&#xff0c;正逐渐成为企业级应用的标配。本文将探讨验证码短信API如何为企业级安全验证提供坚实保障。 验证码短信 API 的优…

MySQL-SQL-DQL

DQL-介绍 DQL-语法 基本查询 1、查询多个字段 2、设置别名 3、去除重复记录 条件查询 1、语法 2、条件 聚合函数 1、介绍 2、常见的聚合函数 3、语法 分组查询 1、语法 2、where与having区别 排序查询 1、语法 2、排序方式 分页查询 1、语法 DQL-执行顺序

关于在微信小程序中使用taro + react-hook后销毁函数无法执行的问题

问题&#xff1a; 在 taro中使用navigageTo() 跳转路由后hook中useEffect 的return函数没有执行 没有执行return函数 框架版本&#xff1a; tarojs: 3.6 react: 18.0 原因&#xff1a; 使用navigateTo() 跳转路由的话并不会销毁页面和组件&#xff0c;会加入一…

智能小程序环境配置流程

App 与智能小程序 在用户使用 App 扫描小程序的二维码或者点击设备&#xff0c;尝试进入小程序时&#xff0c;系统会对 App 当前环境与小程序所需运行环境进行比对&#xff0c;确定环境配置兼容后&#xff0c;App 才能启动并运行小程序。 比对规则中&#xff0c;主要涉及&…

「webpack面试系列」说说你对webpack的理解?解决了什么问题?(收藏好,用时好找)

文章目录 一、背景模块化 二、问题三、是什么webpack的能力&#xff1a; 一、背景 Webpack 最初的目标是实现前端项目的模块化&#xff0c;旨在更高效地管理和维护项目中的每一个资源 模块化 最早的时候&#xff0c;我们会通过文件划分的形式实现模块化&#xff0c;也就是将…

【计算机网络】应用层——HTTP 协议(一)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】 本专栏旨在分享学习计算机网络的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 一、什么是 HTTP 协…

Redis(六)

1、Redis的缓存淘汰策略 1.1、内存配置 首先查看Redis最大的占用内存&#xff0c;打开redis配置文件&#xff0c;设置maxmemory参数&#xff0c;maxmemory是bytes字节类型&#xff0c;注意转换。 打开配置文件发现没有配置&#xff0c;那么默认是多少的内存&#xff0c;是这样…

第2章-OSI参考模型与TCP/IP模型

目录 1. 引入 2. OSI参考模型 2.1. 物理层 2.2. 数据链路层 2.3. 网络层 2.4. 传输层 2.5. 会话层 2.6. 表示层 2.7. 应用层 3. 数据的封装与解封装 4. TCP/IP模型 4.1. 背景引入 4.2. TCP/IP模型&#xff08;4层&#xff09; 4.3. 拓展 1. 引入 1&#xff09;产…

Visual Studio2022实用使用技巧集

前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具&#xff0c;掌握一些Visual Studio实用的搜索、查找、替换技巧可以帮助我们大大提高工作效率从而避免996。 Visual Studio更多实用技巧 https://github.com/YSGStudyHards/DotNetGuide 代码和功能搜…

记一次 stackoverflowerror 线上排查过程

一.线上 stackOverFlowError xxx日,突然收到线上日志关键字频繁告警 classCastException.从字面上的报警来看,仅仅是类型转换异常,查看细则发现其实是 stackOverFlowError.很多同学面试的时候总会被问到有没有遇到过线上stackOverFlowError?有么有遇到栈溢出?具体栈溢出怎么来…

植物神经功能紊乱是什么?

植物神经也叫自律神经&#xff0c;它是一种自发的&#xff0c;非主观意识控制的&#xff0c;低级的神经活动。包括呼吸的、心律的、汗腺的、胃肠道的调节等等&#xff0c;都叫植物神经功能调节。 植物神经它的一旦出现了障碍可以有两种倾向&#xff0c;一种倾向就是出汗、兴奋…

Spring Boot3整合knife4j(swagger3)

目录 1.前置条件 2.导依赖 3.配置 1.前置条件 已经初始化好一个spring boot项目且版本为3X&#xff0c;项目可正常启动。 作者版本为3.2.2最新版 2.导依赖 knife4j官网&#xff1a; Knife4j 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j (xiaominfo.com)http…

Docker初次体验:WSL+Docker+portanier

文章目录 前言Docker是什么&#xff1f;Docker的优点Docker的使用场景&#xff1a;一件安装 Docker安装开启虚拟化安装wsl下载慢的请看这个下载成功 安装Docker修改Docker安装位置 配置Docker安装portanier&#xff08;可视化的Docker操作页面&#xff09;登录网址 总结 前言 …