一 爬楼梯
class Solution:
def climbStairs(self, n: int) -> int:
"""
dp[n]存放到达第n个台阶时有几种方法
dp[0]就是平地
dp[1]就是踏上第一个台阶
"""
dp = [0 for i in range(n+1)]
dp[0] = 0
dp[1] = 1
if n >=2:
# dp[2]也是需要设定的初始值,但是应该在n>=2的时候在设置
# 不然n<2的时候设置超出索引范围
dp[2] = 2
if n>=3:
for i in range(3,n+1):
dp[i] =dp[i-1]+dp[i-2]
return dp[n]# 返回的是dp[n]不是dp[n+1],前面的range(n+1)已经让索引对齐
二 打家劫舍
题目链接:
注意:长度为n的nums的最后一个索引是n-1 索引的边界没处理好会非常痛苦
思路一开始就想对了,后面一直爆超出索引范围,一直在想是不是逻辑上出错,结构后面发现
只是for i in range(3, n):写成了for i in range(3, n+1):导致后面的nums[i]出现错误,因为长度为n的nums最后一个元素的索引是nums[n-1]
思路:经典的动态规划思想,因为不能相连,但是又要力求最多,所以,在长度大于等于3的情况下他的前2个和前3个必有一个抢了(不会出现间隔三个不抢)。维护到最后。最后两个中至少一个抢了,返回大者
每次选这两个中的大者与本身的价值相加就是抢完这件房子后的收获。
class Solution:
def rob(self, nums: list) -> int:
n = len(nums)
dp = [0 for i in range(n)]
dp[0] = nums[0]
if n >= 2:
dp[1] = nums[1]
if n >= 3:
dp[2] = max(nums[2] + dp[0], dp[1])
for i in range(3, n):
dp[i] = nums[i] + max(dp[i - 2], dp[i - 3])
return max(dp[n - 1], dp[n - 2])
# 记住长度为n的nums的最后一个索引是n-1
三 删除并获得点数
题目链接:740. 删除并获得点数 - 力扣(LeetCode)
给你一个整数数组 nums
,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i]
,删除它并获得 nums[i]
的点数。之后,你必须删除 所有 等于 nums[i] - 1
和 nums[i] + 1
的元素。
开始你拥有 0
个点数。返回你能通过这些操作获得的最大点数。
思路:
每次选择一个位置时,要根据位置上的数,进行对应位置的删减,但是该删减的数的位置并没有规律。所以我们没法直接在nums上操作(如果要,巨繁琐)。题目这种一路选择下来达到最大值的一般都是动态规划问题。动态规划问题往往在dp数组中存放当前数值然后一直往后走。
每次我们选的值之后,就可以nums中所有的这个值都拿了,这个值+1 和-1 的值不能拿了。我们把所有数值*数值出现次数放到一个列表中。
如果我们给数值和位置加上一定的关系。就相当于走了这个位置相隔位置就不能走了。之后就是打家劫舍问题了。
class Solution:
def deleteAndEarn(self, nums: List[int]) -> int:
max_value = max(nums)
# 因为要让值和索引有对应的关系,相隔位置放的是值+1-1的值,所以
# 就算max中没有这个值也要有位置。根据最大值来创建sums
sums = [0 for i in range(max_value+1)]
for value in nums:
sums[value] += value
# 这里开始变成打家劫舍问题了
n = len(sums)
dp = [0] * n
dp[0] = sums[0]
if n>=2:dp[1] = sums[1]
if n>=3:
dp[2] = max(sums[2]+dp[0],dp[1])
# 前三个值属于初始值特殊设定
for i in range(3,n):
dp[i] = max(sums[i]+dp[i-2],dp[i-3]+sums[i])
return max(dp[n-1],dp[n-2])
四 不同路径
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
初始位置的走法为1,遍历矩阵,到达每个位置的走法数为能走到这个位置的符合的出发点上储存的走法相加。
这里需要注意的是代码中条件判断部分不能写成这样
if i==0 and j==0:continue
if i==0:
dp[i][j] = dp[i][j-1]
if j==0:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
注意 要把并行的条件处理好,不然会多执行一次操作
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 先创建dp矩阵
dp =[[0 for i in range(n)] for j in range(m)]
dp[0][0] = 1
for i in range(m):
for j in range(n):
if i==0 and j==0:continue
if i==0:
dp[i][j] = dp[i][j-1]
elif j==0:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
五 三角形最小路径和
题目链接: 120. 三角形最小路径和 - 力扣(LeetCode)
给定一个三角形 triangle
,找出自顶向下的最小路径和。
每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i
,那么下一步可以移动到下一行的下标 i
或 i + 1
。
一样的选择符合的上一个位置的较优解。设定初始值,处理边界问题
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
m = len(triangle)
for i in range(m):
for j in range(len(triangle[i])):
if i==0 and j==0:continue
if j==0:
triangle[i][j] += triangle[i-1][j]
# 左边界只能来自上一行列索引一样的位置
elif j==len(triangle[i])-1 :
triangle[i][j] += triangle[i-1][j-1]
# 右边界只能来自上一行列索引-1的位置
else:
triangle[i][j] += min(triangle[i-1][j],triangle[i-1][j-1])
# 其他位置选择更短的路径作为上一个位置
return min(triangle[-1])