动态规划练习题③

2915. 和为目标值的最长子序列的长度

给你一个下标从 0 开始的整数数组 nums 和一个整数 target

返回和为 targetnums 子序列中,子序列 长度的最大值 。如果不存在和为 target 的子序列,返回 -1

子序列 指的是从原数组中删除一些或者不删除任何元素后,剩余元素保持原来的顺序构成的数组。

示例 1:

输入:nums = [1,2,3,4,5], target = 9
输出:3
解释:总共有 3 个子序列的和为 9 :[4,5] ,[1,3,5] 和 [2,3,4] 。最长的子序列是 [1,3,5] 和 [2,3,4] 。所以答案为 3 。

示例 2:

输入:nums = [4,1,3,2,1,5], target = 7
输出:4
解释:总共有 5 个子序列的和为 7 :[4,3] ,[4,1,2] ,[4,2,1] ,[1,1,5] 和 [1,3,2,1] 。最长子序列为 [1,3,2,1] 。所以答案为 4 。

示例 3:

输入:nums = [1,1,5,4,5], target = 3
输出:-1
解释:无法得到和为 3 的子序列。

class Solution:
    def lengthOfLongestSubsequence(self, nums: List[int], target: int) -> int:
        """
        # 1.递归
        def dfs(i, target):
            if i < 0:
                if target == 0:
                    return 0
                else:
                    return float("-inf")
            return max(dfs(i - 1, target - nums[i]) + 1, dfs(i - 1, target))

        res = dfs(len(nums) - 1, target)
        return res if res != float("-inf") else -1
        """

        """
        # 2.记忆化搜索
        cache = [[-1 for _ in range(target + 1)] for _ in range(len(nums))]

        def dfs(i, target):

            if target < 0:
                # 如果目标值已经为负数,则直接返回负无穷,加上这一判断条件是因为cache数组有可能越界
                return float("-inf")

            if i < 0:
                if target == 0:
                    return 0
                else:
                    return float("-inf")
            if cache[i][target] != -1:
                return cache[i][target]
            res = max(dfs(i - 1, target - nums[i]) + 1, dfs(i - 1, target))
            cache[i][target] = res
            return res

        res = dfs(len(nums) - 1, target)
        return res if res != float("-inf") else -1
        """

        """
        # 3.递推
        # (1).二维数组
        dp=[[float('-inf') for _ in range(target+1)] for _ in range(len(nums)+1)]
        dp[0][0]=0
        for i,x in enumerate(nums):
            for j in range(target+1):
                if x>j:
                    dp[i+1][j]=dp[i][j]
                else:
                    dp[i+1][j]=max(dp[i][j-x]+1,dp[i][j])
        return dp[-1][-1] if dp[-1][-1]!=float('-inf') else -1

        # (2).滚动数组
        dp=[float('-inf') for _ in range(target+1)]
        dp[0]=0
        for x in nums:
            for j in range(target,x-1,-1):
                    dp[j]=max(dp[j-x]+1,dp[j])
        return dp[-1] if dp[-1]!=float('-inf') else -1
        """


416. 分割等和子集

给你一个 只包含正整数非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

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

        if sum(nums) % 2 != 0:
            return False
        target = sum(nums) // 2

        """
        # 1.递归
        def dfs(i, target):
            # 如果目标值小于0,说明下面继续递归也找不到正确的答案,直接返回False
            if target<0:
                return False
            if i < 0:
                if target == 0:
                    return True
                else:
                    return False
            return dfs(i - 1, target - nums[i]) or dfs(i - 1, target)

        return dfs(len(nums) - 1, target)
        """

        """
        # 2.记忆化搜索
        cache = [[-1 for _ in range(target + 1)] for _ in range(len(nums))]

        def dfs(i, target):
            if target < 0:
                return False
            if i < 0:
                if target == 0:
                    return True
                else:
                    return False
            if cache[i][target] != -1:
                return cache[i][target]
            res = dfs(i - 1, target - nums[i]) or dfs(i - 1, target)
            cache[i][target] = res
            return res

        return dfs(len(nums) - 1, target)
        """

        """
        # 3.递推
        # (1).二维数组
        dp = [[False for _ in range(target + 1)] for _ in range(len(nums) + 1)]
        dp[0][0] = True
        for i, x in enumerate(nums):
            for j in range(target + 1):
                if x > j:
                    dp[i + 1][j] = dp[i][j]
                else:
                    dp[i + 1][j] = dp[i][j - x] or dp[i][j]
        return dp[-1][-1]

        # (2).滚动数组
        dp = [False for _ in range(target + 1)]
        dp[0] = True
        for x in nums:
            for j in range(target, x - 1, -1):
                dp[j] = dp[j - x] or dp[j]
        return dp[-1]
        """


2787. 将一个数字表示成幂的和的方案数

给你两个 整数 nx

请你返回将 n 表示成一些 互不相同 正整数的 x 次幂之和的方案数。换句话说,你需要返回互不相同整数 [n1, n2, ..., nk] 的集合数目,满足 n = n1x + n2x + ... + nkx

由于答案可能非常大,请你将它对 109 + 7 取余后返回。

比方说,n = 160x = 3 ,一个表示 n 的方法是 n = 23 + 33 + 53

示例 1:

输入:n = 10, x = 2
输出:1
解释:我们可以将 n 表示为:n = 32 + 12 = 10 。
这是唯一将 10 表达成不同整数 2 次方之和的方案。

示例 2:

输入:n = 4, x = 1
输出:2
解释:我们可以将 n 按以下方案表示:
- n = 41 = 4 。
- n = 31 + 11 = 4 。

class Solution:
    def numberOfWays(self, n: int, x: int) -> int:
        """
        # 1.递归
        def dfs(i, target):
            if target<0:
                return 0
            if i == 0:
                if target == 0:
                    return 1
                else:
                    return 0
            return dfs(i - 1, target - i**x) + dfs(i - 1, target)
        return dfs(n, n)%(10**9+7)
        """

        """
        # 2.记忆化搜索
        cache = [[-1 for _ in range(n + 1)] for _ in range(n + 1)]

        def dfs(i, target):
            if target < 0:
                return 0
            if i == 0:
                if target == 0:
                    return 1
                else:
                    return 0
            if cache[i][target] != -1:
                return cache[i][target]
            res = dfs(i - 1, target - i**x) + dfs(i - 1, target)
            cache[i][target] = res
            return res

        return dfs(n, n) % (10**9 + 7)
        """

        """
        # 3.递推
        # (1)二维数组
        dp = [[0 for _ in range(n + 1)] for _ in range(n + 1)]
        dp[0][0] = 1
        for i in range(1, n + 1):
            for j in range(n + 1):
                if i**x > j:
                    dp[i][j] = dp[i - 1][j]
                else:
                    dp[i][j] = dp[i - 1][j - i**x] + dp[i - 1][j]
        return dp[-1][-1] % (10**9 + 7)
        
        # (2).滚动数组
        dp = [0 for _ in range(n + 1)]
        dp[0] = 1
        for i in range(1, n + 1):
            for j in range(n, i**x - 1, -1):
                dp[j] = dp[j - i**x] + dp[j]
        return dp[-1] % (10**9 + 7)
        """


518. 零钱兑换 II

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0

假设每一种面额的硬币有无限个。

题目数据保证结果符合 32 位带符号整数。

示例 1:

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

示例 2:

输入:amount = 3, coins = [2]
输出:0
解释:只用面额 2 的硬币不能凑成总金额 3 。

示例 3:

输入:amount = 10, coins = [10] 
输出:1

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        """
        # 1.递归
        def dfs(i, target):
            # 如果在递归过程中targte值已经小于0,说明下面继续递归值也只会越来越小,直接返回0
            if target < 0:
                return 0
            if i < 0:
                # 只有递到没有硬币可以选且目标值已经变为0了时,说明此时才找到一种方案
                if target == 0:
                    return 1
                else:
                    return 0
            # (完全背包),当前硬币有选和不选两种方案
            # 若选,问题变成在i个硬币中找和为target-coins[i]的金额的子问题
            # 若不选,问题变成在i-1个硬币中找和为target的金额的子问题
            return dfs(i, target - coins[i]) + dfs(i - 1, target)

        return dfs(len(coins) - 1, amount)
        """

        """
        # 2.记忆化搜索
        cache = [[-1 for _ in range(amount + 1)] for _ in range(len(coins))]

        def dfs(i, target):
            if target < 0:
                return 0
            if i < 0:
                if target == 0:
                    return 1
                else:
                    return 0
            if cache[i][target] != -1:
                return cache[i][target]
            res = dfs(i, target - coins[i]) + dfs(i - 1, target)
            cache[i][target] = res
            return res

        return dfs(len(coins) - 1, amount)
        """

        """
        # 3.递推
        # (1).二维数组
        dp = [[0 for _ in range(amount + 1)] for _ in range(len(coins) + 1)]
        dp[0][0] = 1  # 由上面的dfs边界条件判断可得出
        for i, x in enumerate(coins):
            for j in range(amount + 1):
                if x > j:
                    dp[i + 1][j] = dp[i][j]
                else:
                    dp[i + 1][j] = dp[i + 1][j - x] + dp[i][j]
        return dp[-1][-1]
        """
        # (2).滚动数组
        dp = [0 for _ in range(amount + 1)]
        dp[0] = 1 
        for x in coins:
            for j in range(x, amount + 1):
                dp[j] = dp[j - x] + dp[j]
        return dp[-1]


279. 完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,14916 都是完全平方数,而 311 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

class Solution:
    def numSquares(self, n: int) -> int:
        """
        # 1.递归
        def dfs(i, target):
            if target < 0:
                # 该方案不合适,直接返回无穷大
                return float("inf")
            if i == 1:
                if target >= 0:
                    # 只能由target个1来组成
                    return target
                else:
                    return float("inf")
            return min(dfs(i, target - i**2) + 1, dfs(i - 1, target))

        return dfs(int(n**0.5) + 1, n)
        """

        """
        # 2.记忆化搜索
        cache = [[-1 for _ in range(n + 1)] for _ in range(int(n**0.5) + 2)]

        def dfs(i, target):
            if target < 0:
                return float("inf")
            if i == 1:
                if target >= 0:
                    return target
                else:
                    return float("inf")
            if cache[i][target] != -1:
                return cache[i][target]
            res = min(dfs(i, target - i**2) + 1, dfs(i - 1, target))
            cache[i][target] = res
            return res

        return dfs(int(n**0.5) + 1, n)
        """

        """
        # 3.递推
        # (1).二维数组
        dp = [[float("inf") for _ in range(n + 1)] for _ in range(int(n**0.5) + 1)]
        dp[0][0] = 0
        for i in range(1, int(n**0.5) + 1):
            for j in range(n + 1):
                if i**2 > j:
                    dp[i][j] = dp[i - 1][j]
                else:
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - i**2] + 1)
        return dp[-1][-1]
        """

        # (2).滚动数组
        dp = [float("inf") for _ in range(n + 1)]
        dp[0] = 0
        for i in range(1, int(n**0.5) + 1):
            for j in range(i**2, n + 1):
                dp[j] = min(dp[j], dp[j - i**2] + 1)
        return dp[-1]

你可能感兴趣的:(python,算法,动态规划,算法,python,力扣)