LeetCode刷题笔记之动态规划(持续更新)

前言

本篇博客记录本人在LeetCode上练习动态规划算法的记录,分为简单、中等、困难三个等级,每次刷题记录也都会附上时间,方便阅览。

简单

[2022/10/4 : 7道]

【509. 斐波那契数】

原题链接:https://leetcode.cn/problems/fibonacci-number/

在这里插入图片描述

代码

class Solution:
    def fib(self, n: int) -> int:
        if n < 2:
            return n
        
        a1, a2, a3 = 0, 0, 1
        for i in range(2, n + 1):
            a1, a2 = a2, a3
            a3 = a1 + a2
        return a3

【1137. 第 N 个泰波那契数】

原题链接:https://leetcode.cn/problems/n-th-tribonacci-number/
在这里插入图片描述

代码

class Solution:
    def tribonacci(self, n: int) -> int:
        if n == 0:
            return 0
        if n <= 2:
            return 1
        x, y, z = 0, 1, 1
        for i in range(3, n + 1):
            s = x + y + z
            x, y, z= y, z, s
        return s

【70. 爬楼梯】

原题链接:https://leetcode.cn/problems/climbing-stairs/
在这里插入图片描述

思路:
首先初始化,到第一层楼梯可以爬一个阶梯,有一种方式,爬第二层可以一次爬一个台阶,也可以爬两个,有两种方式。此后的第N层楼梯既可由N-2台阶爬两次,也可以由N-1层楼梯爬一个台阶获得,则递推关系式:
f ( x ) = { 1 x = 1 2 x = 2 f ( x − 1 ) + f ( x − 2 ) x ≥ 3 f(x)= \begin{cases} 1 & x = 1\\ 2 & x = 2\\ f(x-1)+f(x-2) & x \geq 3\\ \end{cases} f(x)= 12f(x1)+f(x2)x=1x=2x3

代码

class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1:
            return 1
        if n == 2:
            return 2
        a, b = 1, 2
        for i in range(3, n + 1):
            c = a + b
            a, b = b, c
        return c

【118. 杨辉三角】

原题链接:https://leetcode.cn/problems/pascals-triangle/
在这里插入图片描述

代码

class Solution:
    def generate(self, n) -> List[List[int]]:
        res = []
        for i in range(1, n + 1):
            tmp = [0 for _ in range(i)]
            res.append(tmp)
        for i in range(n):
            res[i][0], res[i][i] = 1, 1
        for i in range(2, n):
            for j in range(1, i):
                res[i][j] = res[i - 1][j] + res[i - 1][j - 1]
        return res

【119. 杨辉三角 II】

原题链接:https://leetcode.cn/problems/pascals-triangle-ii/
在这里插入图片描述

代码

class Solution:
    def getRow(self, n: int) -> List[int]:
        res = []
        for i in range(1, n + 2):
            tmp = [0 for _ in range(i)]
            res.append(tmp)
        for i in range(n + 1):
            res[i][0], res[i][i] = 1, 1
        for i in range(2, n + 1):
            for j in range(1, i):
                res[i][j] = res[i - 1][j] + res[i - 1][j - 1]
        
        return res[n]

【121. 买卖股票的最佳时机】

原题链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
在这里插入图片描述

思路:
在一次遍历中,保存价格的最小值,再依次算当天股票价格与最低价格的差值,取最大,即买卖股票的最佳时机。

代码

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        minn = max(prices)
        profit = 0
        for i in prices:
            minn = min(i, minn)
            profit = max(i - minn, profit)
        return profit

【338. 比特位计数】

原题链接:https://leetcode.cn/problems/counting-bits/
在这里插入图片描述

思路:
1的二进制表示1,2的二进制表示10,3的二进制表示为11,4的二进制表示为100,5的二进制表示为101,5%2=1 5的二进制表示1的个数等于2的二进制表示1的个数加5%2,可以得到递推关系式: f ( x ) = f ( x / 2 ) + x % 2 f(x)=f(x/2)+x\%2 f(x)=f(x/2)+x%2

代码

class Solution:
    def countBits(self, n: int) -> List[int]:
        f = [0 for i in range(n + 1)]
        for i in range(n + 1):
            f[i] = f[i // 2] + i % 2
        return f

[2022/10/6 : 2道]

【392. 判断子序列】

原题链接:https://leetcode.cn/problems/is-subsequence/
在这里插入图片描述

思路:
本题用动态规划的方法求解,和求最大公共子序列的长度问题类似,判断所求的最大公共子序列的长度是否等于给定字符串的长度,相等则可判断该字符串为另一个字符串的子序列。递推公式为: { d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 , s [ i ] = t [ j ] d p [ i ] [ j ] = m a x ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j ] ) , s [ i ] ≠ t [ j ] \begin{cases} dp[i][j] = dp[i - 1][j - 1] + 1, & s[i] =t[j] \\ dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]), & s[i] \neq t[j] \\ \end{cases} {dp[i][j]=dp[i1][j1]+1,dp[i][j]=max(dp[i][j1],dp[i1][j]),s[i]=t[j]s[i]=t[j]

代码:

class Solution:
    def isSubsequence(self, s: str, t: str) -> bool:
        slen = len(s)
        tlen = len(t)
        if slen > tlen:
            return False
        dp = [[0] * (tlen + 1) for _ in range(slen + 1)]
        for i in range(1, slen + 1):
            for j in range(1, tlen + 1):
                if s[i - 1] == t[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1] + 1
                else:
                    dp[i][j] = max(dp[i][j - 1], dp[i - 1][j])
        
        return dp[slen][tlen] == slen

【746. 使用最小花费爬楼梯】

原题链接:https://leetcode.cn/problems/min-cost-climbing-stairs/
在这里插入图片描述

思路:
首先初始化dp数组,dp[0] = dp[1] = 0,此后爬到第n阶的最小花费可以看作爬到第n-1阶花费加上n-1的费用与爬到第n-2阶花费加上n-2的费用的最小值,递推关系式为:
d p [ i ] = { 0 0 ≤ i ≤ 1 m i n ( d p [ i − 1 ] + c o s t [ i − 1 ] , d p [ i − 2 ] + c o s t [ i − 2 ] ) i ≥ 2 dp[i]= \begin{cases} 0 & 0\leq i \leq1 \\ min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]) & i \geq 2 \end{cases} dp[i]={0min(dp[i1]+cost[i1],dp[i2]+cost[i2])0i1i2

代码

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        dp = [0 for _ in range(n + 1)]
        dp[0] = dp[1] = 0
        for i in range(2, n + 1):
            dp[i] = min(dp[i - 2] + cost[i - 2], dp[i - 1] + cost[i - 1])
        return dp[n]

中等

[2022/10/6 : 2道]

【198. 打家劫舍】

原题链接:https://leetcode.cn/problems/house-robber/
在这里插入图片描述

思路:
声明一个二维数组 d p dp dp,维度为 ( n + 1 ) ∗ 2 (n+1) * 2 (n+1)2,初始化数组元素为0。 i i i表示第 i i i个房子, d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示抢劫第 i i i个房子的总价值, d p [ i ] [ 1 ] dp[i][1] dp[i][1]表示不抢劫第 i i i个房子的总价值。抢劫第 i i i个房子,则不能抢劫第 i − 1 i-1 i1个房子,再加上第 i i i个房子的价值。不抢劫第 i i i个房子,则总价值等于抢劫第 i − 1 i-1 i1个房子和不抢劫第 i − 1 i-1 i1个房子中的最大值。可以得到递推关系式为:
{ d p [ i ] [ 0 ] = d p [ i ] [ 1 ] = 0 i = 0 d p [ i ] [ 0 ] = d p [ i − 1 ] [ 1 ] + n u m s [ i − 1 ] , d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] ) 0 ≤ i ≤ n \begin{cases} dp[i][0] = dp[i][1] = 0 & i = 0 \\ dp[i][0] = dp[i - 1][1] + nums[i - 1], dp[i][1] = max(dp[i - 1][1], dp[i - 1][0]) & 0 \le i \leq n \end{cases} {dp[i][0]=dp[i][1]=0dp[i][0]=dp[i1][1]+nums[i1],dp[i][1]=max(dp[i1][1],dp[i1][0])i=00in

代码

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [[0] * 2 for _ in range(n + 1)]
        for i in range(1, n + 1):
            # 0 rob and 1 not rob
            dp[i][0] = dp[i - 1][1] + nums[i - 1]
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0])
        return max(dp[n])

【213. 打家劫舍 II】

原题链接:https://leetcode.cn/problems/house-robber-ii/
在这里插入图片描述

思路:
与上一题的唯一区别是第 1 1 1个和第 n n n个房子不能同时打劫,所以可以算 [ 1 , n − 1 ] [1,n-1] [1,n1]的总价值和 [ 2 , n ] [2,n] [2,n]的总价值的最大值即可。

代码

# 法1
class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        dp1 = [[0] * 2 for _ in range(n + 1)]
        dp2 = [[0] * 2 for _ in range(n + 1)]
        for i in range(1, n):
            # 0 rob and 1 not rob
            dp1[i][0] = dp1[i - 1][1] + nums[i - 1]
            # 不偷第i个
            dp1[i][1] = max(dp1[i - 1][1], dp1[i - 1][0])
        v1 = max(dp1[n - 1])
        for i in range(2, n + 1):
            # 0 rob and 1 not rob
            dp2[i][0] = dp2[i - 1][1] + nums[i - 1]
            # 不偷第i个
            dp2[i][1] = max(dp2[i - 1][1], dp2[i - 1][0])
        v2 = max(dp2[n])
        return max(v1, v2)
# 法2
class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 1:
            return nums[0]
        dp = [0 for _ in range(n + 1)]
        dp[0] = 0
        dp[1] = nums[0]
        for i in range(2, n):
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1])
        v1 = dp[n - 1]
        dp[1] = 0
        dp[2] = nums[1]
        for i in range(3, n + 1):
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1])
        v2 = dp[n]
        return max(v1, v2)

困难

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值