Go&Java算法之子集

83 阅读2分钟

这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战

子集

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

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

 

示例 1:

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

输入:nums = [0] 输出:[[],[0]]  

题解

算法一:DFS回溯(Java)

其实子集也是一种组合问题,因为它的集合是无序的,子集{1,2} 和 子集{2,1}是一样的。

那么既然是无序,取过的元素不会重复取,写回溯算法的时候,for就要从startIndex开始,而不是从0开始!

单看每个元素,都有两种选择:选入子集,或不选入子集。

比如[1,2,3],先看1,选1或不选1,都会再看2,选2或不选2,以此类推。

考察当前枚举的数,基于选它而继续,是一个递归分支;基于不选它而继续,又是一个分支。

  • 用索引index代表当前递归考察的数nums[index]
  • index越界时,说明所有数字考察完了,得到一个解,把它加入解集,结束当前递归分支。
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if (nums == null || nums.length == 0) {
            List<Integer> list = new ArrayList<Integer>();
            result.add(list);
            return result;
        }
        List<Integer> list = new ArrayList<Integer>();
        // Arrays.sort(nums);
        help(result, nums, list, 0);
        return result;
    }

    private void help(List<List<Integer>> result, int[] nums, List<Integer> list, int start) {
        result.add(new ArrayList<>(list));
        for (int i = start; i < nums.length; i++) {
            list.add(nums[i]);
            help(result, nums, list, i+1);
            list.remove(list.size() - 1);
        }
    }
}

时间复杂度:O(N*2^N)

空间复杂度:O(N)

算法二:DFS回溯(Go)

思路同上

func subsets(nums []int) (ans [][]int) {
    set := []int{}
    var dfs func(int)
    dfs = func(cur int) {
        if cur == len(nums) {
            ans = append(ans, append([]int(nil), set...))
            return
        }
        set = append(set, nums[cur])
        dfs(cur + 1)
        set = set[:len(set)-1]
        dfs(cur + 1)
    }
    dfs(0)
    return
}

时间复杂度:O(N*2^N)

空间复杂度:O(N)