算法:动态规划相关题目

  1. 给定一个矩阵m,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。
    思路:经典动态规划,生成辅助矩阵,二维动态规划。
    dp[i][j] 表示从左上角走到(i,j)位置的最小路径和,到达dp[i][j]有两种方案,从左边的点dp[i][j-1]向右走,或者从上边的点dp[i-1][j]向下走。
def minSum(matrix):
    n = len(matrix)
    m = len(matrix[0])
    grid = [[None] * m for _ in range(n)]
    print(grid)
    for i in range(n):
        for j in range(m):
            if i-1 >=0 and j-1 >=0:
                up = grid[i - 1][j]
                left = grid[i][j - 1]
                grid[i][j] = min(up, left) + matrix[i][j] #重点动规公式
            elif i - 1 >= 0 and j - 1 < 0:
                grid[i][j] = grid[i - 1][j] + matrix[i][j]
            elif i-1<0 and j-1>=0:
                grid[i][j] = grid[i][j - 1] + matrix[i][j]
            else:
                grid[i][j] = matrix[i][j]
        print(i, grid)
    return grid[-1][-1]

matrix = [[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
print(minSum(matrix))
  1. 给定数组arr,返回arr的最长递增子序列长度。比如arr=[2,1,5,3,6,4,8,9,7],最长递增子序列为[1,3,4,8,9],返回子序列长度5.
    思路:同 leetcode 300
    dp[i]表示必须以arr[i]这个数结尾的情况下,arr[0,…,i]中的最大递增子序列长度。
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        dp = [1] * len(nums)
        for i in range(1, len(nums)):
            for j in range(0, i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i], dp[j]+1)
        return max(dp)
  1. 给定两个字符串,str1和str2,返回两个字符串的最长公共子序列
    思路:同leetcode 1143
    经典二维动态规划,dp[i][j]表示str1[0:i]与str2[0:j]的最长公共子序列长度。
    变体:最长连续公共子序列(最长连续子串),对子串要求更严格,当 text1[i] != text2[j]时,dp[i][j] = 0。
    def longestCommonSubsequence(self, text1, text2):
        """
        :type text1: str
        :type text2: str
        :rtype: int
        """
        n = len(text1)
        m = len(text2)
        dp = [[0]*m for _ in range(n)]
        for i in range(n):
            for j in range(m):
                if i-1>=0 and j-1>=0:
                    if text1[i] == text2[j]:
                        dp[i][j] = max(dp[i-1][j-1]+1, dp[i-1][j], dp[i][j-1])
                    else:
                        dp[i][j] = max(dp[i-1][j], dp[i][j-1])
                elif i-1>=0 and j-1<0:
                    if text1[i] == text2[j]:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i-1][j]
                elif i-1<0 and j-1>=0:
                    if text1[i] == text2[j]:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = dp[i][j-1]
                else:
                    if text1[i] == text2[j]:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = 0
        return dp[-1][-1]
  1. 一个背包有一定的承重W,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。
    思路:经典动态规划,背包问题。
def bag01(values, weights,W):
    """
    values: 物品的价值数组
    weights: 物品的重量数组
    W: 背包的承重
    """
    N = len(values)
    dp = [[0]*(W+1) for _ in range(N)] #N*(W+1)
    for i in range(N):
        for j in range(W+1):
            # last1 = dp[i-1][j]
            # last2 = dp[i-1][j-weights[i]] + values[i]
            if i-1>=0 and j-weights[i]>=0:
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i]] + values[i])
            elif i-1>=0 and j-weights[i]<0:
                dp[i][j] = dp[i-1][j]
            elif i-1<0 and j-weights[i]>=0:
                dp[i][j] = values[i]
            else:
                dp[i][j] = 0
        print(dp)
    return dp[-1][-1]
  1. 给定两个字符串 str1 和 str2,再给定三个整数 ic、dc和rc,分别代表插入、删除和替换一个字符的代价。返回将 str1 编辑成 str2 的最小代价。
    思路:给定二维动规矩阵dp[M+1][N+1],其中dp[i][j]表示从str1[0:i-1]到str2[0:j-1]编辑的最小代价。一共有四种可能情况:
    str1[0:i-1]和str2[0:j-2] + 插入一个字符,插入j-1
    str1[0:i-2]和str2[0:j-1] + 删除一个字符,删除i-1
    i-1!=j-1: str1[0:i-2]和str2[0:j-2] + 替换一个字符,i-1替换j-1
    i-1==j-1: 直接使用str1[0:i-2]和str2[0:j-2] 的代价
    参考leetcode 72
def editCost(str1, str2, ic, dc, rc):
    m = len(str1)
    n = len(str2)
    dp = [[0]*(n+1) for _ in range(m+1)]
    # 第一列,将str1转为"",删除掉str1的元素
    for i in range(1,m+1):
        dp[i][0] = dc*i
    # 第一行,将""转为str2,插入str2的元素
    for j in range(1,n+1):
        dp[0][j] = ic*j
    #其他,四种情况
    for i in range(1,m+1):
        for j in range(1,n+1):
            dc_cost = dp[i-1][j] + dc
            ic_cost = dp[i][j-1] + ic
            rc_cost = dp[i-1][j-1]
            if str1[i-1]!=str2[j-1]:
                rc_cost = rc_cost + rc
            dp[i][j] = min(dc_cost, ic_cost, rc_cost)
    return dp[-1][-1]

str1 = "abcdef"
str2 = "abcddd"

print(editCost(str1,str2,1,1,1))
  1. 给定数组arr,arr中所有值为正数且不重复,每个值代表一种面值的货币,每种面值的货币可以使用任意张。再给定整数aim代表要找的钱数,求换钱有多少种方法?
    在这里插入图片描述
    leetcode 322 零钱兑换 题目类似
    牛客 CD19 换钱的方法数 二维动态规划,超时
def changeNum(coins, aim):
    aim = int(aim)
    n = len(coins)

    dp = [[0] * (aim + 1) for _ in range(n)]

    # 第一列填充,aim=0时
    for i in range(0, n):
        dp[i][0] = 1

    # 第一行填充,仅使用一种硬币时
    k = aim // coins[0]
    for i in range(0, k + 1):
        dp[0][i * coins[0]] = 1

    for line in dp:
        print(line)
    # print(dp)

    # 填充剩余
    for i in range(1, n):
        for j in range(1, aim + 1):
            if j - coins[i] >= 0:
                dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i]]
            else:
                dp[i][j] = dp[i - 1][j]

    return dp[-1][-1]

coins = [5,10,25,1]
n = 15
print(changeNum(coins,n))

优化成一维动态规划

def changeNumDim1(coins, aim):
    aim = int(aim)
    n = len(coins)

    dp = [0] * (aim + 1)
    dp[0] = 1

    for i in range(n):
        for j in range(coins[i], aim+1):
            dp[j] = dp[j] + dp[j-coins[i]]
        print(dp)

    return dp[-1]
  1. 查找两个数组的最长公共子数组并输出这个公共子数组,要求子数组是连续的。
    思路:dp[i][j]表示以 i,j 结尾的最长公共子数组, 如果a[i]!=b[j]. dp[i][j]=0.
    def findLength(self, nums1, nums2):
        m = len(nums1)
        n = len(nums2)
        dp = [[0]*(n+1) for _ in range(m+1)] #构建dp数组记忆
        result = -1
        idx = -1
        for i in range(1,m+1):
            for j in range(1,n+1):
                if nums1[i-1] == nums2[j-1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = 0
                if dp[i][j] > result:
                    result = dp[i][j]
                    idx = i
        print('result', nums1[i-result:i+1])
        return result
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值