代码随想录算法训练营第二十五天|491.递增子序列、46.全排列、47.全排列 II

今日题目

491.递增子序列

题目链接:491. 非递减子序列 - 力扣(LeetCode)

思考:本题给出的数组已经是递增顺序,数组元素存在重复,且在一个结果中可以出现两个相同元素作为递增序列,因此在遍历树结构时,同一层级需要元素去重,这里采用集合记录元素使用情况。其余部分采用递归+回溯思想实现。

代码:

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

        def dfs(nums, start, path, ans):
            if len(path) > 1:
                ans.append(path[:])

            use_set = set()
            for i in range(start, len(nums)):
                if (path and nums[i] < path[-1]) or nums[i] in use_set:
                    continue
                use_set.add(nums[i])
                path.append(nums[i])
                dfs(nums, i+1, path, ans)
                path.pop()

        dfs(nums, 0, path, ans)
        return ans
46.全排列

题目链接:46. 全排列 - 力扣(LeetCode)

思考:本题要返回数组的全排列,因此在遍历树结构得到的每一个path长度都与原始数组相同,遍历完数组所有元素程序终止。这里也要求元素不能重复使用,因此在遍历过一个元素后需要在去掉该元素的剩余元素中遍历,故也可以采用上一题的思想,用集合记录元素使用情况。

这里采用优化方案,使用集合操作 s - {x}高效移除已用元素,确保排列不重复使用数字。相比标记数组更节省空间。

每次递归传入新的集合 s - {x},无需显式回溯状态。path[i] 会被后续选择覆盖,自然实现回溯。

代码:

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        ans = []
        path = [0] * n
        def dfs(i,s):
            if i == n:
                ans.append(path.copy())
                return
            for x in s:
                path[i] = x
                dfs(i+1, s - {x})
        dfs(0, set(nums))
        return ans
47.全排列 II

题目链接:

思考:上一题全排列没有重复元素,采用集合记录可选元素,每次选取一个元素后集合就剔除该元素。本题数组中存在重复元素,可以考虑记录元素的下标使用情况。

这种情况需要首先对数组排序,然后处理存在相等的元素的情况下,只用一个。在递归和回溯时要同时处理path和used。

代码:

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        nums.sort()
        ans = []
        path = []
        used = [False] * n

        def dfs(nums, used, path, ans):
            if len(path) == n:
                ans.append(path[:])
                return
            for i in range(n):
                if (i > 0 and nums[i] == nums[i-1] and not used[i-1]) or used[i]:
                    continue
                used[i] = True
                path.append(nums[i])
                dfs(nums, used, path, ans)
                path.pop()
                used[i] = False

        dfs(nums, used, path, ans)
        return ans

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值