78. 子集

78. 子集

mid

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

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

示例 1:

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

示例 2:

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

DFS

经典的组合问题,一棵二叉树,选或不选

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func subsets(nums []int) [][]int {
	res := make([][]int, 0)
	var dfs func(subset []int, layer int)
	dfs = func(subset []int, layer int) {
		if layer == len(nums) {
			subsetCopy := make([]int, len(subset))
			copy(subsetCopy, subset)
			res = append(res, subsetCopy)
			return
		}
		dfs(subset, layer+1)
		dfs(append(subset, nums[layer]), layer+1)
	}
	dfs([]int{},0)
	return res
}

更标准的 DFS 回溯写法

然而内存消耗并没有区别。。。

其实这道题是用不上回溯的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func subsets(nums []int) [][]int {
	res := make([][]int, 0)
	subset := make([]int, 0)
	var dfs func(layer int)
	dfs = func(layer int) {
		if layer == len(nums) {
			subsetCopy := make([]int, len(subset))
			copy(subsetCopy, subset)
			res = append(res, subsetCopy)
			return
		}
		dfs(layer + 1)
		subset = append(subset, nums[layer])
		dfs(layer + 1)
		subset = subset[:len(subset)-1]
	}
	dfs(0)
	return res
}

这样写切片拷贝,好像更快一点:

1
res = append(res, append([]int{}, subset...))

另一种思路

之前的思路是收集一棵树所有的叶子节点,也可以收集树的所有节点

image-20220707142558977

这样的话就有一个 for 循环选取剩余集合中的每个元素了,用 startIndex 避免重复(因为是组合问题)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func subsets(nums []int) [][]int {
	res := make([][]int, 0)
	var dfs func(subset []int, startIndex int)
	dfs = func(subset []int, startIndex int) {
		res = append(res, append([]int{}, subset...))
		if startIndex == len(nums) {
			// 终止条件 可以不加
			return
		}
		for i := startIndex; i < len(nums); i++ {
			subset = append(subset, nums[i])
			dfs(subset, i+1)
			subset = subset[:len(subset)-1]
		}
	}
	dfs([]int{}, 0)
	return res
}

这才是真回溯