20天速通LeetCodeday17:一维动态规划

前言

今日练习目的:从一维动态规划入手,理解"子问题是更小规模的父问题与子问题最优解"两大核心特征,建立"用历史结果推导当前解"的思维。

重要思维突破:理解动态规划本质是用数组记录子问题答案,吧自顶向下的递归,转化为自底向上的递推,但要注意,并非所有递归都可以转为动态规划。

509:斐波那契数列

题目要求:给定一个整数n,求第n个斐波那契数

核心思路(一维动态规划)

用数组dpi存储第i个斐波那契数

遍历从2到n

dpi=dpi-1+dpi-2

代码实现

java 复制代码
class Solution {
    public int fib(int n) {
        if(n==0) return 0;
        if(n==1) return 1;

        int[] dp=new int[n+1];//dp[i]表示第i个斐波那契数
        dp[0]=0;
        dp[1]=1;

        for(int i=2;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];

    }
}

总结

作为入门的一维动态规划。核心需要理解:一维DP就是沿着线性状态从前往后累积计算,每个状态只依赖前两个状态

53:最大子数组和

题目要求:给定一个整数数组nums,找出一个拦蓄子数组,使得他们的和最大

要求:返回这个最大和

核心思路

假设dpi表示以numsi结尾的最大子数组和:dpi = max(dpi-1 + numsi, numsi)

如果把前面的子数组加上numsi比numsi小-就从numsi重新开始

每一步更新全局最大值maxSum

代码实现

java 复制代码
int n=nums.length;
int[] dp=new int[n]
dp[0]=nums[0];
int maxSum=dp[0];

for(int i=1;i<n;i++){
dp[i]=Math.max(dp[i-1]+nums[i];nums[i]);//状态转移
maxSum=Math.max(maxSum,dp[i]);
}
return maxSum;

总结

本题重点只有一个,就是理解dpi的递增实现

理解dpi = max(dpi-1 + numsi, numsi)就能掌握本题

想要讲的重点是关于递归和一维动态规划的区别

递归的特点是:

自己调用自己,没有记录已经计算过的结果

DP的特点是:

讲递归的重复计算结果记住

用一个数组dpi存储每个状态的结果

自底向上(从小状态开始计算到大状态)

198:打家劫舍

题目要求:

有一个整数数组nums,表示每个房子里的钱,你不能抢相邻的房子,求你能抢到的最大金额。

核心思路

对于每个房子i,有两个选择:

  1. 抢当前房子-就不能抢上一个房子,只能加上dpi-2;
  2. 不抢当前房子-最大金额=dpi-1
    状态转移方程:dpi = max(dpi-1, dpi-2 + numsi)

代码实现

java 复制代码
if(nums.length==0||nums==null) return 0;
if(nums.length==1) return nums[0];

int n=nums.length;
int[] dp=new int[n];
dp[0]=nums[0];
dp[1]=nums[1];

for(int i=2;i<n;i++){
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[i-1];

总结

理解一维动态规划的本质是:用数组记录子问题的答案。通过记录下来 的答案来获得父问题。

也就是说难点在于找出特征方程。

对于本题来说:每一遍历到一个房子i,都面临两个选项;1.抢(代表前一个房子不能抢)2.不抢(抢前一个房子)

dpi=max(dpi-2+numsi,dpi-1)

300:最长递增子序列

题目要求:

给定一个整数数组nums,找到其中最长严格递增子序列长度

核心思路

先定义dpi=以numsi结尾的最长递增子序列长度

状态转移方程:dpi=max(dpj+1) for all j < i and numsj < numsi

对于每个numsi,找前面所有比它小的numsj

初始化dpi=1

代码实现

java 复制代码
if(nums.length==0||nums==null) return 0;
int n=nums.length;
int[] dp=new int[n];
int maxLen=1;
Arrays.fill(dp,1)

for(int i=1;i<n;i++){
for(int j=1;j<n;j++){
if(nums[i]>nums[j]{
dp[i]=Math.max(dp[i],dp[j+1]);
}
}
mxaLen=Math.max(maxLen,dp[i]);
}

总结

本题最具有难度的是想到通过i和j两个变量,一个前一个后来判断递增数组是否增加,命dpi为以numsi为结尾的最长递增子序列长度

状态转移方程:dpi = max(dpj + 1) for all j < i and numsj < numsi

139:单词拆分

题目要求:给定一个字符串s和一个单词字典wordDict

要求:判断是否可以用字典里的单词完全拼接成s。

核心思路

动态规划定义状态:dpi=true/false表示s0...i-1是否可以被字典拆分

状态转移方程:dpi=dpj&&wordDict.contains(sj...i-1)

代码实现

java 复制代码
class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wordSet=new HashSet<>(wordDict);//查找O(1)
        int n=s.length();
        boolean[] dp=new boolean[n+1];
        dp[0]=true;//空字符串可拆分
        
        for(int i=1;i<=n;i++){//子串长度
            for(int j=0;j<i;j++){
                if(dp[j]&&wordSet.contains(s.substring(j,i))){
                    dp[i]=true;
                    break;//找到一个拆分即可
                }
            }
        }
        return dp[n];
    }
}
相关推荐
浅念-1 小时前
动态规划:线性DP——多状态DP与子数组专题笔记
c++·笔记·算法·leetcode·职场和发展·动态规划·力扣
Data analyse4561 小时前
rrweb回放事件资源加载顺序重放校验
前端·人工智能·算法·机器学习·数据分析
昨夜见军贴06161 小时前
原始采样记录数字化落地,IACheck AI 报告文档审核 Agent 实现监测文档校验自动化
人工智能·算法·自动化
微学AI2 小时前
从历史曲线到提前预警:TimechoAI 的时序预测与业务落地实践
人工智能·算法
不会就选b2 小时前
算法日常・每日刷题--<动态规划>26
算法·动态规划
荆棘鸟智能2 小时前
虫情测报灯图像识别算法实践:小目标检测、粘连计数与飞虱细粒度分类
算法·目标检测·分类
爱读书的小胖3 小时前
LeetCode 27. 移除元素(C)解题分析
数据结构·算法
科技小E3 小时前
敏感数据不敢上云训练?本地大模型推理服务器DLTM私有化部署,让训练全程留在企业内网
大数据·算法·自动化
小草cys3 小时前
用 GPT 直接生成可编辑 PPTX 的实操记录,artifact-tool是OpenAICodex环境专用
gpt·算法·pptx
爱读书的小胖3 小时前
Codewars: A Brave New Wordle(C)解题分析
c语言·数据结构·算法