《001 子集》— 【回溯】

151 阅读1分钟

一、题目描述

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

说明:解集不能包含重复的子集。

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

二、题解

(1)回溯

整体思路:

  • 遇到nums的一个元素(包括空集[ ])就把该元素添加进集合tmp,直到tmpsize达到nums数组的大小,然后回溯,怎么回溯?
  • 在本次循环中,先去掉tmp后面的一个元素,因为一次循环中,j 是不会减小,只会增加,所以,每次去掉tmp的最后一个元素,那么就会回溯一层,而每回溯一层,就会去掉tmp的最后一个元素
  • 直到回到j==0处,j然后自增,把nums[j](即nums[1])add进集合tmp
public class Main {
  public static List<List<Integer>> subsets(int[] nums) {
    List<List<Integer>> subsets = new LinkedList<>();
    backtrack(0,nums, subsets, new ArrayList<Integer>());
    return subsets;
  }

  private static void backtrack(int i, int[] nums, List<List<Integer>> ans, ArrayList<Integer> tmp) {
    ans.add(new ArrayList<Integer>(tmp));
    for (int j = i; j < nums.length; j++) {
      tmp.add(nums[j]);
      backtrack(j+1, nums, ans, tmp);
      tmp.remove(tmp.size()-1);
    }
  }
  
  public static void main(String[] args) {
    int[] nums = {1,2,3};
    System.out.println(subsets(nums));
  }
}

复杂度分析

  • 时间复杂度:
    • tmp集合用 ArrayList 只要 1 ms 击败99.31%
    • 用 LinkedList 要 2 ms击败35.92%
    • 时间差别主要在tmp.remove(tmp.size()-1);这里,在数据量不大的情况下,LinkedList 在查找方面用到的时间比较多。
  • 空间复杂度: