代码随想录算法训练营第28天| 78.子集 90.子集2 491.递增子序列

代码随想录系列文章目录

回溯篇 - 子集问题


文章目录

  • 代码随想录系列文章目录
  • 78.子集
  • 90.子集II
  • 491.递增子序列


78.子集

题目链接
组合问题和分割问题都是收集树的叶子节点

而子集问题是找树的所有节点

子集是无序的,子集{1,2} 和 子集{2,1}是一样的。

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

什么时候for可以从0开始呢?求排列问题的时候,就要从0开始
代码随想录算法训练营第28天| 78.子集 90.子集2 491.递增子序列_第1张图片
从图中红线部分,可以看出遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合。

写子集问题,可以不用写出口,一方面是因为收集所有叶子结点,另一方面startIndex >= nums.size(),本身本层for循环本来也结束了。
如果要加出口,if start >= nums.size(): return, 一定要加在res.append(path)之后,否则会漏掉自己

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        def rec(start,path):
            res.append(path)
            for i in range(start,len(nums)):
                rec(i+1,path+[nums[i]])
        rec(0,[])
        return res

90.子集II

题目链接

就是子集加了个每一层上的去重

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        res = []
        nums.sort()
        def rec(start, path):
            res.append(path)
            for i in range(start, len(nums)):
                if i > start and nums[i] == nums[i-1]: continue
                rec(i+1, path+[nums[i]])
        rec(0, [])
        return res

491.递增子序列

题目链接
非常有陷阱的子集问题:
这个递增子序列比较像是取有序的子集。而且本题也要求不能有相同的递增子序列。

这又是子集,又是去重,是不是不由自主的想起了90.子集2, 在那题里,采取了对数组先排序,然后再去重的套路

if i > start and nums[i] == nums[i-1]: continue

但是这道题是求数组里的递增子序列,不能破坏原数组结构,那怎么办呢?

首先我们还是要明确,这个去重是在每层递归逻辑里去重,即每层选过了的元素我们不能再选,如图:
代码随想录算法训练营第28天| 78.子集 90.子集2 491.递增子序列_第2张图片
我们这道题的在每层遍历逻辑里去重,可以采用unordered set 或者数组就行,把遍历到的nums[i],装进数组,如果在这一层再次遍历到同一数字,那么continue就行了,这样就实现了每层的去重逻辑。

这种做法要记住

这道题的出口也有讲究,子集问题,原本不用加出口限制,收集所有结点path, 但是这道题是递增子序列,需要len(path) >= 2我们再把它加进结果集。

class Solution:
    def findSubsequences(self, nums: List[int]) -> List[List[int]]:
        res = []
        def rec(start, path):
            if len(path) >= 2:
                res.append(path)
            
            hashmap = []
            for i in range(start, len(nums)):
                if nums[i] not in hashmap:
                    hashmap.append(nums[i])
                else: continue
                if not path or nums[i] >= path[-1]:
                    rec(i+1, path+[nums[i]])
        rec(0, [])
        return res

你可能感兴趣的:(代码随想录算法训练营打卡,算法,leetcode,职场和发展)