代码随想录|Day25|回溯05|491.非递减子序列、46.全排列、47.全排列II

491. 非递减子序列

本题并不能像 90.子集II 那样,使用排序进行树层去重。虽然题目没有明确不能排序,但如果排序了,集合本身就是递增子序列,这是LeetCode示例2中没有出现的。

所以本题的关键在于,如何在不排序的情况下对树层去重。在树层遍历的时候(也就是for循环),我们维护一个 used 数组,记录已经使用过的元素。

class Solution:
    def findSubsequences(self, nums: List[int]) -> List[List[int]]:

        def backtrack(startIndex, path):

            used = set()
            for i in range(startIndex, len(nums)):
                # 如果元素小于path中的最后一个元素,无法构成递增
                # 如果元素已经在同一树层被使用过,则需要去重
                if (path and nums[i] < path[-1]) or nums[i] in used:
                    continue

                used.add(nums[i])
                path.append(nums[i])
                # 收集符合条件的节点
                if len(path) > 1:
                    result.append(path[:])

                backtrack(i + 1, path)
                path.pop()

        result = []
        backtrack(startIndex = 0, path = [])
        return result

46.全排列

排列问题和组合问题的区别在于,顺序不同算作不同排列。在组合问题中,我们定义 startIndex 确保每次递归只能向后探索,否则可能出现 [1, 2] [2, 1] 这种重复组合。在排列问题中,我们不再需要 startIndex,只需确保同一元素不被重复选取

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        def backtrack(path):
            # 全排列在叶子结点处收集结果
            if len(path) == len(nums):
                result.append(path[:])
                return
            
            for i in range(len(nums)):
                # 只要同一元素不被重复选取
                # 顺序不同算作不同排列
                if nums[i] in path:
                    continue
                path.append(nums[i])
                backtrack(path)
                path.pop()

        result = []
        backtrack(path = [])
        return result

47.全排列II

本题多了一个存在重复数字的条件,因此为了确保同一元素不被重复选取,采用上一题的方法并不行。因为我们只是不能取同一元素,但如果两个元素的值相同呢?我们需要借助used数组 通过位置来判断而不是值。

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:

        def backtrack(path, used):
            if len(path) == len(nums):
                result.append(path[:])
                return
            
            for i in range(len(nums)):
                # 避免同一元素被多次使用
                if used[i]:
                    continue
                # 树层去重,由于 nums 包含重复数字,结果需要去重
                if i > 0 and nums[i] == nums[i-1] and used[i-1] == False:
                    continue
                used[i] = True
                path.append(nums[i])
                backtrack(path, used)
                path.pop()
                used[i] = False
        
        result = []
        nums.sort()
        backtrack(path = [], used = [False] * len(nums))
        return result
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值