从零学算法78

这篇具有很好参考价值的文章主要介绍了从零学算法78。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

78.给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]文章来源地址https://www.toymoban.com/news/detail-805600.html

  • 如果将该题想象成一棵 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。
    从零学算法78,算法学习,# 递归,# 回溯,算法
  • 因此,比如例子 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);
      }
    

到了这里,关于从零学算法78的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 从零学算法154

    154 .已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到: 若旋转 4 次,则可以得到 [4,5,6,7,0,1,4] 若旋转 7 次,则可以得到 [0,1,4,4,5,6,7] 注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为

    2024年02月13日
    浏览(33)
  • 从零学算法50

    50 .实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。 示例 1: 输入:x = 2.00000, n = 10 输出:1024.00000 示例 2: 输入:x = 2.10000, n = 3 输出:9.26100 示例 3: 输入:x = 2.00000, n = -2 输出:0.25000 解释:2-2 = 1/22 = 1/4 = 0.25 还真没我想的那么简单,这题可以学一下快速幂,我就直

    2024年02月07日
    浏览(32)
  • 从零学算法55

    55 .给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例 1: 输入:nums = [2,3,1,1,4] 输出:true 解释:可以先跳 1 步,从下标

    2024年02月21日
    浏览(55)
  • 从零学算法34

    34 .给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target,返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 示例 1: 输入:nums = [5,7,7,8,8,10], target

    2024年02月13日
    浏览(38)
  • 从零学算法113

    113 .给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1: 输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 输出:[[5,4,11,2],[5,8,4,5]] 示例 2: 输入:root = [1,2,3]

    2024年02月11日
    浏览(35)
  • 从零学算法

    1575.给你一个 互不相同 的整数数组,其中 locations[i] 表示第 i 个城市的位置。同时给你 start,finish 和 fuel 分别表示出发城市、目的地城市和你初始拥有的汽油总量 每一步中,如果你在城市 i ,你可以选择任意一个城市 j ,满足 j != i 且 0 = j locations.length ,并移动到城市 j 。从

    2024年02月06日
    浏览(24)
  • 从零学算法(LCR 180)

    文件组合 .待传输文件被切分成多个部分,按照原排列顺序,每部分文件编号均为一个 正整数(至少含有两个文件)。传输要求为:连续文件编号总和为接收方指定数字 target 的所有文件。请返回所有符合该要求的文件传输组合列表。 注意,返回时需遵循以下规则: 每种组合

    2024年02月07日
    浏览(31)
  • 从零学算法(剑指 Offer 45)

    输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。 示例 1: 输入: [10,2] 输出: “102” 示例 2: 输入: [3,30,34,5,9] 输出: “3033459” 我的原始人解法:直接冒泡排序,把最先应该拼接的那个数不断后移,然后拼接即可。关键就

    2024年02月10日
    浏览(36)
  • 从零学算法 (剑指 Offer 13)

    地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+

    2024年02月11日
    浏览(32)
  • 递归、搜索与回溯算法(专题一:递归)

    往期文章(希望小伙伴们在看这篇文章之前,看一下往期文章) (1)递归、搜索与回溯算法(专题零:解释回溯算法中涉及到的名词)【回溯算法入门必看】-CSDN博客 接下来我会用几道题,来让同学们利用我在专题零中提到的 递归的宏观思想 来解决这些题目。 目录 1. 汉诺

    2024年01月25日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包