DataWhale编程实践:Task02——动态规划

具体算法思想参见
team-learning-program/LeetCodeClassification/2.动态规划.md
下面是对上面链接中的各个leetcode题给出的代码测试版本(注意函数括号中的一些内容被删掉了,因为不需要)。另外,子序列和子串是不一样的概念,子序列可以是原字符串中不连续的字符组成的字符串,只要每个字符出现的顺序和原字符串一致,而子串必须是由原字符串中的连续字符组成的串串。

# Leetcode 300.最长上升子序列
def lengthOfLIS(nums):
    if not nums: return 0  # 判断边界条件
    dp = [1] * len(nums)  # 初始化dp数组状态
    for i in range(len(nums)):
        for j in range(i):
            if nums[i] > nums[j]:  # 根据题目所求得到状态转移方程
                dp[i] = max(dp[i], dp[j] + 1)
    return max(dp)  # 确定输出状态


# Leetcode 674.最长连续递增序列
def findLengthOfLCIS(nums):
    if not nums: return 0  # 判断边界条件
    dp = [1] * len(nums)  # 初始化dp数组状态
    # 注意需要得到前一个数,所以从1开始遍历,否则会超出范围
    for i in range(1, len(nums)):
        if nums[i] > nums[i - 1]:  # 根据题目所求得到状态转移方程
            dp[i] = dp[i - 1] + 1
        else:
            dp[i] = 1
    return max(dp)  # 确定输出状态


# Leetcode5. 最长回文子串
def longestPalindrome(s):
    length = len(s)
    if length < 2:  # 判断边界条件
        return s
    dp = [[False for _ in range(length)] for _ in range(length)]  # 定义dp状态矩阵

    max_len = 1
    start = 0  # 后续记录回文串初试位置
    for j in range(1, length):
        for i in range(j):
            # 矩阵中逐个遍历
            if s[i] == s[j]:
                if j - i < 3:
                    dp[i][j] = True
                else:
                    dp[i][j] = dp[i + 1][j - 1]
            if dp[i][j]:  # 记录位置,返回有效答案
                cur_len = j - i + 1
                if cur_len > max_len:
                    max_len = cur_len
                    start = i
    return s[start:start + max_len]


# Leetcode516. 最长回文子序列
def longestPalindromeSubseq(s):
    n = len(s)
    dp = [[0] * n for _ in range(n)]  # 定义动态规划状态转移矩阵
    for i in range(n):  # 初始化对角线,单个字符子序列就是1
        dp[i][i] = 1
    for i in range(n, -1, -1):  # 从右下角开始往上遍历
        for j in range(i + 1, n):
            if s[i] == s[j]:  # 当两个字符相等时,直接子字符串加2
                dp[i][j] = dp[i + 1][j - 1] + 2
            else:  # 不相等时,取某边最长的字符
                dp[i][j] = max(dp[i][j - 1], dp[i + 1][j])
    return dp[0][-1]  # 返回右上角位置的状态就是最长


# Leetcode72. 编辑距离
def minDistance(word1, word2):
    # m,n 表示两个字符串的长度
    m = len(word1)
    n = len(word2)
    # 构建二维数组来存储子问题
    dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
    # 考虑边界条件,第一行和第一列的条件
    for i in range(n + 1):
        dp[0][i] = i  # 对于第一行,每次操作都是前一次操作基础上增加一个单位的操作
    for j in range(m + 1):
        dp[j][0] = j  # 对于第一列也一样,所以应该是1,2,3,4,5...
    for i in range(1, m + 1):  # 对其他情况进行填充
        for j in range(1, n + 1):
            if word1[i - 1] == word2[j - 1]:  # 当最后一个字符相等的时候,就不会产生任何操作代价,所以与dp[i-1][j-1]一样
                dp[i][j] = dp[i - 1][j - 1]
            else:
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1  # 分别对应删除,添加和替换操作
    return dp[-1][-1]  # 返回最终状态就是所求最小的编辑距离


# Leetcode198. 打家劫舍
def rob(nums):
    if not nums:  # 特殊情况处理
        return 0
    if len(nums) == 1:
        return nums[0]
    n = len(nums)
    dp = [0] * n  # 初始化状态转移数组
    dp[0] = nums[0]  # 第一个边界值处理
    dp[1] = max(nums[0], nums[1])  # 第二个边界值处理
    for i in range(2, n):
        dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])  # 状态转移方程
    return dp[-1]


# Leetcode213. 打家劫舍 II
def robC(nums):
    if not nums:
        return 0
    elif len(nums) <= 2:
        return max(nums)

    def helper(nums):
        if len(nums) <= 2:
            return max(nums)
        dp = [0] * len(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for i in range(2, len(nums)):
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
        return dp[-1]

    return max(helper(nums[1:]), helper(nums[:-1]))


if __name__ == "__main__":
    # Leetcode 300.最长上升子序列
    nums = [10, 9, 2, 5, 3, 7, 101, 18]
    maxLeng = lengthOfLIS(nums)
    print("最长上升子序列长度: {0}".format(maxLeng))

    # Leetcode 674.最长连续递增序列
    nums1 = [1, 3, 5, 4, 7]
    maxLenAse = findLengthOfLCIS(nums1)
    print("最长连续递增序列长度: {0}".format(maxLenAse))


    # Leetcode5. 最长回文子串
    strIN = "babad"
    cycSub = longestPalindrome(strIN)
    print("最长回文子串的一种情况: {0}".format(cycSub))

    # Leetcode516. 最长回文子序列
    strIn = "bbbab"
    cycSubSeqL = longestPalindromeSubseq(strIn)
    print("最长回文子序列长度: {0}".format(cycSubSeqL))

    # Leetcode72. 编辑距离
    word1 = "horse"
    word2 = "ros"
    minDist = minDistance(word1, word2)
    print("将 '{0}' 转换成 '{1}' 所使用的最少操作数: {2}".format(word1, word2, minDist))

    # Leetcode198. 打家劫舍
    numsR = [1, 2, 3, 1]
    robMon = rob(numsR)
    print("偷窃到的最高金额: {0}".format(robMon))

    # Leetcode213. 打家劫舍 II
    numsRC = [2, 3, 2]
    robMonC = robC(numsRC)
    print("偷窃到的最高金额: {0}".format(robMonC))

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值