动态规划高频算法题Python代码

目录

最大正方形 

二叉搜索树的数量

最长公共子序列

最长公共子串

买卖股票的最佳时机(只能买卖一次)

买卖股票的最佳时机(可以买卖多次)

买卖股票的最佳时机(可以买卖两次)

买卖股票的最佳时机(可以买卖K次)

最长的括号子串


最大正方形 

在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。

class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return 0
        dp = [[0] * len(matrix[0]) for _ in range(len(matrix))]
        max_redius = 0
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                if matrix[i][j] == '1':
                    if i == 0 or j == 0:
                        dp[i][j] = 1
                    else:
                        dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
                    if dp[i][j] > max_redius:
                        max_redius = dp[i][j]
        return max_redius * max_redius

对于每个位置(i, j),检查该位置的值:如果是0,则dp[i][j]=0,因为该位置不可能构成正方形;如果该位置为1,则dp[i][j]的值还要看其上方、左方和左上方的dp值决定,状态转移方程为dp(i,j)=min(dp(i-1,j),dp(i,j-1),dp(i-1,j-1))+1

二叉搜索树的数量

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 

class Solution:
    def numTrees(self, n: int) -> int:
        dp = [0] * (n + 1)
        dp[0], dp[1] = 1, 1
        for i in range(2, n + 1):
            for j in range(1, i + 1):
                dp[i] += dp[j - 1] * dp[i - j]
        return dp[n]

n=1时,只有一棵树;n=2时,直观可得有2棵树;n=3时,可以分成1,2,3分别为头结点,若1为头结点,右子树有2个结点,等价于n=2时的布局数量,若2为头结点,左右分别为1个结点,等价于n=1时的布局数量,若3为头结点,左子树有2个结点,等价于n=2时的布局数量,因此,轮着试一遍,n个结点的搜索树数量就是分别取中间值为根结点时的左右子树可能数量之积的和。即,递推公式为dp[i]+=dp[j-1]*dp[i-j]

最长公共子序列

给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列。

class Solution:
    def LCS(self , s1 , s2 ):
        # write code here
        if not s1 or not s2: return -1
        m, n = len(s1), len(s2)
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if s1[i - 1] == s2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                else:
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
        if dp[m][n] == 0: return -1
        row, col = m, n
        lcs = ''
        cur = dp[m][n]
        while True:
            if s1[row - 1] == s2[col - 1]:
                lcs = s1[row - 1] + lcs
                cur -= 1
                if cur <= 0: return lcs
                row -= 1
                col -= 1
            else:
                if dp[row - 1][col] > dp[row][col - 1]:
                    row -= 1
                else:
                    col -= 1

注意:不要求连续的子序列

最长公共子串

给定两个字符串str1和str2, 输出两个字符串的最长公共子串

题目保证str1和str2的最长公共子串存在且唯一。

class Solution:
    def LCS(self , str1 , str2 ):
        # write code here
        dp = [[0] * (len(str2) + 1) for _ in range(len(str1) + 1)]
        max_num = 0
        end = 0
        for i in range(1, len(str1) + 1):
            for j in range(1, len(str2) + 1):
                if str1[i - 1] == str2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                if dp[i][j] > max_num:
                    max_num = dp[i][j]
                    end = i
        return str1[end - max_num: end]

注意:要求连续的子序列

买卖股票的最佳时机(只能买卖一次)

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [[0] * 2 for _ in range(len(prices))]
        dp[0][0] = -prices[0]
        for i in range(1, len(prices)):
            dp[i][0] = max(dp[i - 1][0], -prices[i])
            dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
        return dp[-1][1]

买卖股票的最佳时机(可以买卖多次)

给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [[0] * 2 for _ in range(len(prices))]
        dp[0][0] = -prices[0]
        for i in range(1, len(prices)):
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i])
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i])
        return dp[-1][1]

买卖股票的最佳时机(可以买卖两次)

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [[0] * 5 for _ in range(len(prices))]
        dp[0][1] = -prices[0]
        dp[0][3] = -prices[0]
        for i in range(1, len(prices)):
            dp[i][0] = dp[i - 1][0]
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])
            dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i])
            dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i])
            dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i])
        return dp[-1][-1]

买卖股票的最佳时机(可以买卖K次)

给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        if len(prices) == 0: return 0
        dp = [[0] * (2*k + 1) for _ in range(len(prices))]
        for j in range(1, 2*k + 1, 2):
            dp[0][j] = -prices[0]
        
        for i in range(1, len(prices)):
            for j in range(0, 2*k - 1, 2):
                dp[i][1 + j] = max(dp[i - 1][1 + j], dp[i - 1][j] - prices[i])
                dp[i][2 + j] = max(dp[i - 1][2 + j], dp[i - 1][1 + j] + prices[i])
        return dp[-1][-1]

最长的括号子串

给出一个长度为 nn 的,仅包含字符 '(' 和 ')' 的字符串,计算最长的格式正确的括号子串的长度。

例1: 对于字符串 "(()" 来说,最长的格式正确的子串是 "()" ,长度为 2 .

例2:对于字符串 ")()())" , 来说, 最长的格式正确的子串是 "()()" ,长度为 4 .

要求时间复杂度 O(n) ,空间复杂度 O(1).

class Solution:
    def longestValidParentheses(self , s ):
        # write code here
        stack = [-1]
        ans = 0
        for i in range(len(s)):
            if s[i] == '(':
                stack.append(i)
            else:
                if len(stack) > 1:
                    stack.pop()
                    ans = max(ans, i - stack[-1])
                else:
                    stack[-1] = i
        return ans

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值