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 分钟前
数据结构进阶(五):最短路径——Dijkstra 与 Floyd 算法
数据结构·算法
fengxin_rou3 分钟前
LeetCode链表经典五题:从相交到环形,双指针的妙用
算法·leetcode·链表
KaMeidebaby3 分钟前
卡梅德生物技术快报|抗原如何自己检测?FAdV-4 重组抗原制备与 ELISA 体系技术调试指南
前端·人工智能·物联网·算法·百度
却道天凉_好个秋7 分钟前
HEVC(二):如何实现并行处理
人工智能·算法·计算机视觉·hevc·瓦片技术·波前并行处理wpp
wayz118 分钟前
Momentum:QQE(定量定性估计)技术指标详解
算法·金融·数据分析·量化交易·特征工程
Dontla9 分钟前
聚类找不到簇原因分析(聚类失败)(DBSCAN聚类算法、eps参数、Epsilon参数、最大允许距离)
算法·数据挖掘·聚类
写代码写到手抽筋8 小时前
5G上行DCI字段判定:端口 流数 PMI选择详解
java·算法·5g
xieliyu.8 小时前
Java算法精讲:双指针(二)
java·开发语言·算法
wayz119 小时前
Momentum:PSL(心理线指标)技术指标详解
算法·金融·数据分析·量化交易·特征工程
8Qi810 小时前
LeetCode 213:打家劫舍 II(House Robber II)—— 题解 ✅
算法·leetcode·职场和发展·动态规划