dfs 排列组合——找所有子集

17. 子集

中文

English

给定一个含不同整数的集合,返回其所有的子集。

样例

样例 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记录遍历路径即可。

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)

第二种写法是使用位运算,也比较直观,代码很容易写出来:

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不用走到叶子节点):

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

所以代码如下:

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()

原文地址:https://www.cnblogs.com/bonelee/p/11667428.html

时间: 2024-08-02 18:44:39

dfs 排列组合——找所有子集的相关文章

Codeforces 991E. Bus Number (DFS+排列组合)

解题思路 将每个数字出现的次数存在一个数组num[]中(与顺序无关). 将出现过的数字i从1到num[i]遍历.(i from 0 to 9) 得到要使用的数字次数数组a[]. 对于每一种a使用排列组合公式: ? ans += 上面那个公式.(每用一次这个公式对应一个a) 排列组合公式注解 减号左边表示的是sum个数字全排列并去重. 减号右边表示的是从a[0]中选出一个0当做第一个数字,并对其他数字全排列并去重. 抱歉,写的可能比较混乱,还有部分细节需要读者处理. 代码 #include<bit

第一节.排列组合

总结:什么时候用回溯法? 如果题目要求求出所有满足条件的解,一般来说是用回溯法,记住回溯法的模板,对不同的题目只需要修改这个条件即可. 回溯法的本质是在问题的解空间树上做深度优先搜索(DFS).这节课主要讲了四个排列组合的问题,分别是子集,带重复元素的子集,全排列,带重复元素的全排列.本文分析求子集的问题,给出程序模板.       题目:给定一个含不同整数的集合,返回其所有的子集.       样例: 如果 S = [1,2,3],有如下的解: [ [3], [1], [2], [1,2,3]

Day4:T3搜索 T4数学题排列组合

T3:搜索 很出名的题吧,费解的开关 同T2一样也是一题很考思考的 附上题解再解释吧: 对于每个状态,算法只需要枚举第一行改变哪些灯的状态,只要第一行的状态固定了,接下来的状态改变方法都是唯一的:每一行需要改变状态的位置都在上一行中不亮的灯的正下面,因为只有这样才能使上一行的灯全亮.我们枚举第一行的状态改变方法(共2^5种),对于每种方法都依次改变下面几行的状态使上面一行灯全亮.到最后一行我们需要判断是否最后一行也恰好全亮,并更新最小步数. 首先需要找到第一行的状态,怎么写?枚举深搜啊 找到了其

HDU 1521 排列组合 搜索

排列组合 Problem Description 有n种物品,并且知道每种物品的数量.要求从中选出m件物品的排列数.例如有两种物品A,B,并且数量都是1,从中选2件物品,则排列有"AB","BA"两种. Input 每组输入数据有两行,第一行是二个数n,m(1<=m,n<=10),表示物品数,第二行有n个数,分别表示这n件物品的数量. Output 对应每组数据输出排列数.(任何运算不会超出2^31的范围) Sample Input 2 2 1 1 Sa

HDU--5396(区间dp+排列组合)

做这道题的时候,想到会不会是dp,然后发现dp可做,但是一直被自己坑到死. 枚举最后合并的那个位置,然后对于加减号的,分成的前后两个部分都有不同的组合方法, (a1+a2........) +  (b1,b2.............)         对于每个a,被加b的个数的阶乘次 ,对于每个b,被加a的个数的阶乘次 减法同理 乘法特殊一点 (a1+a2........) *  (b1,b2.............)  乘法分配率,直接将两部分的总和相乘即可 想到这些还远远没有结束,因为最

排列组合问题

一.不同元素子集问题 78. Subsets Given a set of distinct integers, nums, return all possible subsets. 给定一组非重复数字,求出所有可能的子集 解析: 例如 [1,2,3],解法: 首先放[],然后往已有的[]中放1 1. 首先放1 此时已有[ [], 1 ] 2. 然后对[ [], 1 ] 放2 于是此时有 [ [], [1], [2], [1,2] ] 3. 然后对[ [], [1], [2], [1,2] ]

排列组合问题之圆形分布

1.问题1.1 团团坐有一张圆桌,坐了A,B,C,D四个人,已知,D在A的右边,C在D的对面,请问A,B,C,D,的坐次? 解答:这个问题相对简单,我们纸上画一画,就能画出他们的可能的位置了 但是,可能还有一种解,比如我们把A,B,C,D依次右转一个位,也是满足条件的,而且只要保持他们的相对位置不变,依次右转n个位都是问题的解,而且还有个有趣的事情,当他们转了一圈(即右转4个位)后,他们右回到原位了 2.圆形分布上面这个问题就是一种圆形分布,那么他和直线分布的区别在哪里呢?又有什么联系呢?上面文

SPOJ - AMR11H Array Diversity (水题排列组合或容斥)

题意:给定一个序列,让你求两种数,一个是求一个子序列,包含最大值和最小值,再就是求一个子集包含最大值和最小值. 析:求子序列,从前往记录一下最大值和最小值的位置,然后从前往后扫一遍,每个位置求一下数目就好. 求子集可以用排列组合解决,很简单,假设最大值个数是 n,最小值的数是 m,总数是 N,答案就是 (2^n-1) * (2^m-1)*2^(N-m-n), 当然要特殊判断最大值和最小值相等的时候. 当然也可以用容斥来求,就是总数 - 不是最大值的数目 - 不是最小值的数目 + 不是最大值也不是

排列组合知识

1.在不全相异的n个物体中,其中有n1个物体是相同的,n2个物体是相同的,……nk个物体是相同的.全部物体的种类数为k,则这n个物体的全排列数为 n!/(n1!*n2!*……*nk!) 2.用n-1条边将n个顶点连接的图有n^(n-2)个. 3.圆周排列 从N个元素中取出R个元素形成圆周排列,排列数为A(N,R)/R; 同理,N个元素的圆周排列数为(N-1)!; 4.按字典序生成下一个排列组合 ①从后往前找第一个正序的尾下标i,pi>p(i-1),pi>p(i+1): ②找p(i-1)后面其大