dfs 排列组合——找所有子集(重复元素和不重复元素)
17. 子集
给定一个含不同整数的集合,返回其所有的子集。
样例
样例 1:
输入:[0]
输出:
[
[],
[0]
]
样例 2:
输入:[1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
挑战
你可以同时用递归与非递归的方式解决么?
注意事项
子集中的元素排列必须是非降序的,解集必须不包含重复的子集。
时间复杂度是O(2^n),本质就是在做二叉树的dfs。[1,2,3]举例:
root
/ \
不选中1 选中1
/ \ / \
不选中2 选中2 不选中2 选中2
。。。。。
使用dfs记录遍历路径即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class Solution: """ @param nums: A set of numbers @return: A list of lists """ def subsets( self , nums): # write your code here path, results = [],[] self .helper( sorted (nums), 0 , path, results) return results def helper( self , nums, index, path, results): if index = = len (nums): results.append( list (path)) return path.append(nums[index]) self .helper(nums, index + 1 , path, results) path.pop() self .helper(nums, index + 1 , path, results) |
第二种写法是使用位运算,也比较直观,代码很容易写出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Solution: """ @param nums: A set of numbers @return: A list of lists """ def subsets( self , nums): # write your code here nums = sorted (nums) n = len (nums) results = [] for i in range ( 1 <<n): results.append( self .get_num(nums, i, n)) return results def get_num( self , nums, num, cnt): result = [] for i in range (cnt): if num & ( 1 <<i): result.append(nums[i]) return result |
第三种写法是使用for dfs写法,看下面的图,以【1,2,3】为例:
root (path=[])
|
----------------------------------------
| | |
1 2 3
/ \ |
2 3 3
/
3
在遍历上述树的过程中将path全部记录下来(path不用走到叶子节点):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Solution: """ @param nums: A set of numbers @return: A list of lists """ def subsets( self , nums): # write your code here nums = sorted (nums) path, result = [], [] self .dfs(nums, 0 , path, result) return result def dfs( self , nums, index, path, result): result.append( list (path)) if index = = len (nums): return for i in range (index, len (nums)): path.append(nums[i]) self .dfs(nums, i + 1 , path, result) path.pop() |
含有重复元素的子集问题,例如【1,2,2,3】
root (path=[])
|
----------------------------------------
| | | |
1 2 2(重复) 3
/ \ / \ |
2 3 2 3 3
/ \ |
2 3 3
|
3
又例如【1,1,2,3】
root (path=[])
|
----------------|-------------------------
| 1(重复) | |
1 / \ 2 3
/ | \ 2 3 |
1 2 3 | 3
/ \ | 3
2 3 3
|
3
所以代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Solution: """ @param nums: A set of numbers. @return: A list of lists. All valid subsets. """ def subsetsWithDup( self , nums): # write your code here nums = sorted (nums) path, result = [], [] self .dfs(nums, 0 , path, result) return result def dfs( self , nums, index, path, result): result.append( list (path)) for i in range (index, len (nums)): if i > 0 and nums[i] = = nums[i - 1 ] and i > index: continue path.append(nums[i]) self .dfs(nums, i + 1 , path, result) path.pop() |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」