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

 

posted @ 2019-10-13 18:04  bonelee  阅读(1185)  评论(0编辑  收藏  举报