【回溯】B000_子集 I(回溯 | 位运算 | dfs)

一、题目描述

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。

输入: nums = [1,2,3]
输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

二、题解

(1) 回溯

利用回溯方法生成子集,即对于每个元素,都有试探放入或不放入集合中的两个选择。

  • 选择放入该元素,递归的进行后续元素的选择,完成放入该元素后续所有元素的试探;
  • 之后将其拿出,即再进行一次选择不放入该元素,递归的进行后续元素的选择,完成不放入该元素后续所有元素的试探。

例如:元素数组: n u m s = [ 1 , 2 , 3 , 4 , 5 , … ] nums = [1, 2, 3, 4, 5,…] nums=[1,2,3,4,5,],子集生成数组 i t e m [   ] = [   ] item[\ ] = [\ ] item[ ]=[ ]
对于元素 1 1 1

  • 选择放入 i t e m item item 集合, i t e m = [ 1 ] item = [1] item=[1],继续递归处理后续 [ 2 , 3 , 4 , 5 , … ] [2,3,4,5,…] [2,3,4,5,] 元素; i t e m = [ 1 , … ] item = [1,…] item=[1,]
  • 选择不放入 i t e m item item i t e m = [   ] item = [\ ] item=[ ],继续递归处理后续 [ 2 , 3 , 4 , 5 , … ] [2,3,4,5,…] [2,3,4,5,] 元素; i t e m = [ … ] item = […] item=[]

整个过程可以总结为下图:
在这里插入图片描述

public class Main {
  public static List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> subset = new LinkedList<List<Integer>>();
    LinkedList<Integer> item = new LinkedList<Integer>();
    subset.add(item);
    backtrack2(0, nums, subset, item);
    return subset;
  }

  /**
   * @date: 1/31/2020 6:27 PM
   * @Execution info:1ms 击败 99.13% 的j,MB 击败 5.1% 的j
   */
  private static void backtrack2(int i, int[] nums, List<List<Integer>> ans, LinkedList<Integer> item) {
    if(i == nums.length)  
      return;
    item.addLast(nums[i]);
    ans.add(new LinkedList<Integer>(item));
    backtrack2(i+1, nums, ans, item);
    item.pollLast();
    backtrack2(i+1, nums, ans, item);
  }
  
  public static void main(String[] args) {
    int[] nums = {1,2,3};
    System.out.println(subsets(nums));
  }
}

复杂度分析

  • 时间复杂度: O ( 2 n ) O(2^n) O(2n),时间差别主要在 t m p . r e m o v e ( t m p . s i z e ( ) − 1 ) ; tmp.remove(tmp.size()-1); tmp.remove(tmp.size()1); 这里,在数据量不大的情况下, L i n k e d L i s t LinkedList LinkedList 在查找方面用到的时间比较多。
  • 空间复杂度: O ( 2 n ) O(2^n) O(2n)

(2) 位运算

若一个集合有三个元素 A , B , C A, B, C A,B,C,则 3 3 3 个元素有 2 3 = 8 2^3 = 8 23=8 种组成集合的方式,用 0 − 7 0-7 07 表示这些集合。
在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值