leetcode_day5_筑基期_《绝境求生》

12 阅读5分钟

目录


前言

碎碎念:步步为营,状态转移

本系列《绝境求生》记录转码算法筑基过程,以代码随想录为纲学习,leetcode_hot_100练手,在此记录思考过程,方便过后复现。内容比较粗糙仅便于笔者厘清思路,复盘总结。

添加了代码逻辑这一部分内容


提示:以下是本篇文章正文内容

动态规划

特点:运筹学上最优化算法,题型是求最值,重叠子问题,最优子结构,!!状态转移方程

把复杂问题拆解成小问题,再由小问题的答案推导出大问题的答案(即记住之前做过的事情,避免重复计算,提高效率)

状态定义:用某个变量或数组代表某个小问题的答案

状态转移方程:大问题的答案=小问题答案的组合的数学表达式

初始化条件:最小的问题,不用推导就知道答案

一、198打家劫舍

题目描述

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4

示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12

1.模型

简单理解?

决定是否偷第i家,偷就不能偷i-1,不偷那最大金额就是偷到第i-1收工

能不能用图示意?

None

初始化条件?

双指针解题初始化就是 

prepre=nums[0], pre=max(nums[0], nums[1])  

边界条件?

没得偷的情况,只有一家可以被偷

i=0, i=1

代码逻辑?

  • cur = max(pre, prepre + nums[i])

    • pre 对应「不偷第 i 间」的金额(前 i-1 间的最大金额);
    • prepre + nums[i] 对应「偷第 i 间」的金额(前 i-2 间的最大金额 + 当前房金额);

指针更新的顺序不可以反,必须先更新prepre 再更新pre。 否则上一个pre会被覆盖

优化法

用双指针法

用变量替代数组

#双指针
def solution(nums):
    n=len(nums)
    if n==0:
        return 0
    if n==1:
        return nums[0]
    prepre=nums[0]
    pre=max(nums[0],nums[1])
    for i in range(2,n):
        cur=max(pre,prepre+nums[i])  #
        prepre=pre
        pre=cur
    return pre

细节?

反复强调,确定好数组的值,还有数组下标的含义。即定义好状态

我感觉最容易混乱的就是房间的下标 循环变量i

偷当前房的金额是 prepre+nums[i]  而非 pre+nums[i]

之前见过但没注意到的?

NONE

疑惑点/新知识 ?

NONE

二、746使用最小花费爬楼梯

题目描述

给你一个整数数组 cost,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择爬1 个或 2 个台阶。

你可以选择从下标为 0 或下标为 1的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费

示例

  • 示例 1:输入 cost = [10,15,20] → 输出 15

    • 解释:从下标 1 开始,支付 15,爬 2 个台阶直接到顶 → 总花费 15。
  • 示例 2:输入 cost = [1,100,1,1,1,100,1,1,99,1] → 输出 6

    • 解释:路径 1→3→4→6→7→9,总花费 1+1+1+1+1=6

提示

  • 2 <= cost.length <= 1000
  • 0 <= cost[i] <= 999

1.模型

简单理解?

现在是从每一层开始往上爬1-2个台阶花费不一样,之前是找到爬楼梯的所有方法,现在是在此基础上用其中一个方法爬到target层使得花费最小

注意!!! cost[-1]是 顶层的上一层 而不是顶层

能不能用图示意?

none

初始化条件?

prerpe=cost[0]

pre=cost[1]

边界条件?

剪枝 target=2  return min(cost[0],cost[1])

代码逻辑?

none

暴力法

有但是不想用

优化法

def solution(cost):
    n=len(cost)
    #剪枝
    if n==2:
        return min(cost[0],cost[1])
    #初始化
    prepre=cost[0]
    pre=cost[1]
    for i in range(2,n):
        #最大问题
        cur=min(prepre,pre)+cost[i]
        #双指针更新
        prepre=pre
        pre=cur
    return min(pre,prepre)
 

细节?

用了双指针法就不需要  dp=[0]*n 初始化数组了

之前见过但没注意到的?

1、不要混淆目标:目标是最小花费而不是到达台阶。所以返回的不是 dp[-1],而是 min(dp[-1], dp[-2]),因为顶部在数组末尾的下一个位置。

2、初始化错误:把 dp[0] 或 dp[1] 初始化为 0,忽略了起始台阶需要支付的费用。但是如果前两阶台阶不计费, 那状态方程就是 min(prepre+cost[i-2] , pre+cost[i-1] )


少出头,多装死。即使伤官需要观众