在动态规划的海洋中遨游(一)

news2024/9/24 16:36:14

前言: \textcolor{Green}{前言:} 前言:

💞本专栏用于本人刷算法的过程。主要包含刷题中的感受以及知识点缺陷。对于学习者来说可以作为参考。
目前更新的算法内容会比较多,很多都是通过刷题来进行知识点的总结,其中部分来源于网络总结,如有侵权请联系。💞

文章存在时候,会随着博主的学习过程进行不间断更新,只增不减,请放心使用

目前作者正在刷题,如果想一起交流的可以添加联系方式互相学习~~欢迎大家

动态规划

  • 一、算法介绍
    • 原理
    • 适用的情况
    • 做题步骤:
  • 二、算法实例
    • 1. 最小花费爬楼梯
    • 2. 把数字翻译成字符串
    • 3. 最长公共子序列(二)
    • 4. 最长公共子串
    • 5. 矩阵的最小路径和

一、算法介绍

原理

思想:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法。按顺序求解子阶段,前面子问题的解为后面子问题的求解提供信息。

如果某一问题有很多重叠子问题,使用动态规划是最有效的。

动态规划中每一个状态一定是由上一个状态推导出来。

动态规划算法的基本思想:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果。

适用的情况

  1. 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,称该问题具有最优子结构,即满足最优化原理。
  2. 没有后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说:某状态以后的过程不会影响以前的状态,只与当前状态有关。
  3. 有重叠子问题:子问题之间是不独立的,一个子问题在下一个近阶段可能被多次遇到。(这条性质不是动态规划适用的必要条件但是具备这条性质那么动态规划相对于其他算法就具备一定的优势)。

做题步骤:

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

二、算法实例

1. 最小花费爬楼梯

题目来源:牛客网
等级:简单 \textcolor{OrangeRed}{等级:简单} 等级:简单
涉及方法:动态规划

这道题是非常经典的题目,出题肯定不是这么简单的出

👉题目描述

给定一个整数数组 c o s t cost cost ,其中 c o s t [ i ] cost[i] cost[i] 是从楼梯第 i i i 个台阶向上爬需要支付的费用,下标从 0 0 0开始。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 0 0 或下标为 1 1 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

数据范围:数组长度满足 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105,数组中的值满足 1 ≤ c o s t i ≤ 1 0 4 1 \le cost_i \le 10^4 1costi104

示例1

输入:[2,5,20]
返回值:5
说明:你将从下标为1的台阶开始,支付5 ,向上爬两个台阶,到达楼梯顶部。总花费为5   

示例2

输入:[1,100,1,1,1,90,1,1,80,1]
返回值:6
说明:
你将从下标为 0 的台阶开始。
1.支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
2.支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
3.支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
4.支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
5.支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
6.支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6

👉代码编写

👉👉方法1

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param cost int整型一维数组 
     * @return int整型
     */
    public int minCostClimbingStairs (int[] cost) {
        // write code here
        if (cost.length == 1) return cost[0];
        int dp0 = cost[0], dp1 = cost[1];
        for (int i = 2; i < cost.length; ++i) {
            int tmp = dp1;
            dp1 = Math.min(cost[i] + dp0, cost[i] + dp1);
            dp0 = tmp;
        }
        return dp0 > dp1 ? dp1 : dp0;
    }
}

👉👉方法2

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param cost int整型一维数组 
     * @return int整型
     */
    public int minCostClimbingStairs (int[] cost) {
        // write code here
        int dp[] = new int[cost.length];
        dp[0] = cost[0];
        dp[1] = cost[1];
        for (int i = 2; i < cost.length; ++i) {
            dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
        }
        return Math.min(dp[dp.length - 1], dp[dp.length - 2]);
    }
}

👉 注意点

👉 可以提炼的知识

2. 把数字翻译成字符串

题目来源:牛客网
等级:中等 M e d i u m \textcolor{OrangeRed}{等级:中等 Medium} 等级:中等Medium
涉及方法:动态规划

👉题目描述

有一种将字母编码成数字的方式: ′ a ′ − > 1 , ′ b − > 2 ′ , . . . , ′ z − > 2 6 ′ 'a'->1, 'b->2', ... , 'z->26' a>1,b>2,...,z>26

现在给一串数字,返回有多少种可能的译码结果

数据范围:字符串长度满足 0 < n ≤ 90 0 < n \le 90 0<n90
进阶:空间复杂度 O ( n ) O(n) O(n),时间复杂度 O ( n ) O(n) O(n)

示例1

输入:"12"
返回值:2
说明:2种可能的译码结果(”ab” 或”l”)  

示例2

输入:"31717126241541717"
返回值:192
说明:192种可能的译码结果  

👉代码编写

(该思路来源于官方)

对于普通数组1-9,译码方式只有一种,但是对于11-19,21-26,译码方式有可选择的两种方案,因此我们使用动态规划将两种方案累计。
具体方法:
step 1:用辅助数组dp表示前i个数的译码方法有多少种。
step 2:对于一个数,我们可以直接译码它,也可以将其与前面的1或者2组合起来译码:如果直接译码,则dp[i]=dp[i−1];如果组合译码,则dp[i]=dp[i−2]
step 3:对于只有一种译码方式的,选上种dp[i−1]即可,对于满足两种译码方式(10,20不能)则是dp[i−1]+dp[i−2]
step 4:依次相加,最后的dp[length]即为所求答案。

👉👉方法1

import java.util.*;


public class Solution {
    /**
     * 解码
     * @param nums string字符串 数字串
     * @return int整型
     */
    public int solve (String nums) {
        // write code here
        if (nums.length() == 1 && nums.charAt(nums.length() - 1) == '0'){
            return 0;
        }
        if (nums.length() == 1){
            return nums.length();
        }
        if (nums.charAt(nums.length() - 1) == '0' && 
           nums.charAt(nums.length() - 2) != '1' && nums.charAt(nums.length() - 2) != '2') {
            return 0;
        }
        int dp[] = new int[nums.length() + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= nums.length(); ++i) {
            if ((nums.charAt(i - 2) == '1' && nums.charAt(i - 1) <= '9' && nums.charAt(i - 1) > '0')
                || (nums.charAt(i - 2) == '2' && nums.charAt(i - 1) <= '6' && nums.charAt(i - 1) > '0')) {
                    dp[i] = dp[i - 1] + dp[i - 2];
            } else {
                dp[i] = dp[i - 1];
            }
        }
        return dp[nums.length()];
    }
}

👉 注意点

👉 可以提炼的知识

3. 最长公共子序列(二)

题目来源:牛客网
等级: M e d i u m \textcolor{OrangeRed}{等级:Medium} 等级:Medium
涉及方法: 动态规划

👉题目描述

给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列

数据范围: 0 ≤ ∣ s t r 1 ∣ , ∣ s t r 2 ∣ ≤ 2000 0 \le |str1|,|str2| \le 2000 0str1∣,str2∣2000
要求:空间复杂度 O ( n 2 ) O(n^2) O(n2),时间复杂度 O ( n 2 ) O(n^2) O(n2)

示例1

输入:"1A2C3D4B56","B1D23A456A"
返回值:"123456"

示例2

输入:"abc","def"
返回值:"-1"

示例3

输入:"abc","abc"
返回值:"abc"

示例4

输入:"ab",""
返回值:"-1"

👉代码编写

👉 注意点

  1. 子序列不是子串,子串要求所有字符必须连续,子序列不要求连续,只要求相对位置不变
  2. 注意下列方法,该方法的重点其一是求出最长公共子序列的长度,其二是求出子序列。
  3. 字符串反转reverse(),一般我们直接调用即可。这里我们使用的是(StringBuilder)sb.reverse

👉👉方法1

import java.util.*;


public class Solution {
    /**
     * longest common subsequence
     * @param s1 string字符串 the string
     * @param s2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String s1, String s2) {
        // write code here
        if (s1 == null || s2 == null || s1.length() == 0 || s2.length() == 0) {
            return "-1";
        }

        // 先求最长公共子序列的长度
        int[][] dp = new int[s1.length() + 1][s2.length() + 1];
        for (int i = 1; i <= s1.length(); ++i) {
            char ch1 = s1.charAt(i - 1);
            for (int j = 1; j <= s2.length(); ++j) {
                char ch2 = s2.charAt(j - 1);
                if (ch1 == ch2) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        // 求长度结束

        // 求子序列
        int row = s1.length() + 1, col = s2.length() + 1;
        if (dp[row - 1][col - 1] == 0) {
            return "-1";
        }
        StringBuilder sb = new StringBuilder();
        for (int r = row - 1, c = col - 1; dp[r][c] >= 1;) {
            if (s1.charAt(r - 1) == s2.charAt(c - 1)) {
                sb.append(s1.charAt(r - 1));
                --r;
                --c;
            } else if (dp[r - 1][c] >= dp[r][c - 1]) {
                --r;
            } else {
                --c;
            }
        }
        return sb.reverse().toString();
    }
}

👉 可以提炼的知识

4. 最长公共子串

题目来源:
等级: \textcolor{OrangeRed}{等级:} 等级:
涉及方法:

👉题目描述

给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。

数据范围: 1 ≤ ∣ s t r 1 ∣ , ∣ s t r 2 ∣ ≤ 5000 1 \le |str1|,|str2| \le 5000 1str1∣,str2∣5000
要求: 空间复杂度 O ( n 2 ) 空间复杂度 O(n^2) 空间复杂度O(n2),时间复杂度 O ( n 2 ) O(n^2) O(n2)


示例1

输入:"1AB2345CD","12345EF"
返回值:"2345"

备注: 1 ≤ ∣ s t r 1 ∣ , ∣ s t r 2 ∣ ≤ 5   000 1 \leq |str_1|, |str_2| \leq 5\,000 1str1,str25000

👉代码编写

👉👉方法1

import java.util.*;


public class Solution {
    /**
     * longest common substring
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @return string字符串
     */
    public String LCS (String str1, String str2) {
        // write code here
        int row = str1.length() + 1, col = str2.length() + 1;
        int[][] dp = new int[row][col];
        int max = 0, index = 0;
        for (int i = 1; i < row; ++i) {
            for (int j = 1; j < col; ++j) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    if (max < dp[i][j]) {
                        max = dp[i][j];
                        index = i;
                    }
                }
            }
        }
        return max == 0 ? "-1" : str1.substring(index - max, index);
    }
}

👉 注意点

👉 可以提炼的知识

substring():截取字符串的一部分字符

函数用法

  1. substring(int beginIndex):返回从起始位置到字符串末尾

  2. substring(int beginIndex, int endIndex):返回从起始位置到目标位置之间的字符串,但不包含目标位置。

5. 矩阵的最小路径和

题目来源: 牛客网
等级: M e d i u m \textcolor{OrangeRed}{等级:Medium} 等级:Medium
涉及方法:动态规划

👉题目描述

给定一个 n ∗ m n * m nm 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。

数据范围: 1 ≤ n , m ≤ 500 1 \le n,m\le 500 1n,m500,矩阵中任意值都满足 0 ≤ a i , j ≤ 100 0 \le a_{i,j} \le 100 0ai,j100
要求:时间复杂度 O ( n m ) O(nm) O(nm)

例如:当输入[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]时,对应的返回值为12,
所选择的最小累加和路径如下图所示:


示例1

输入:[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
返回值:12

示例2

输入:[[1,2,3],[1,2,3]]
返回值:7

备注:
1 ≤ n , m ≤ 2000 1 \leq n,m \leq 2000 1n,m2000
1 ≤ a i , j ≤ 100 1 \leq a_{i,j} \leq 100 1ai,j100

👉代码编写

👉 注意点

  1. 这个题目也比较经典,注意dp数组。同时也要看图,图是很好理解的。

👉👉方法1

import java.util.*;


public class Solution {
    /**
     * 
     * @param matrix int整型二维数组 the matrix
     * @return int整型
     */
    public int minPathSum (int[][] matrix) {
        // write code here
        int row = matrix.length, col = matrix[0].length;
        int dp[][] = new int[row][col];
        dp[0][0] = matrix[0][0];
        for (int i = 1; i < col; ++i) {
            dp[0][i] = dp[0][i - 1] + matrix[0][i];
        }
        for (int i = 1; i < row; ++i) {
            dp[i][0] = dp[i - 1][0] + matrix[i][0];
        }
        for (int i = 1; i < row; ++i) {
            for (int j = 1; j < col; ++j) {
                dp[i][j] = matrix[i][j] + Math.min(dp[i -1][j], dp[i][j - 1]);
            }
        }
        return dp[row - 1][col - 1];
    }
}

👉 可以提炼的知识

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/137453.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机SCI论文,很难发表吗?应该如何发表? - 易智编译EaseEditing

首先&#xff0c;找题目需要符合国际标准&#xff0c;但不要缺少创新的探究题目。这个题目可以是最新的技术&#xff0c;也可以是最新的领域&#xff1b; 也可以是探索过很多次的课题。但是如果我们想成功交付&#xff0c;如何创新是我们需要思考的。 其次&#xff0c;因为英语…

为什么有的电源不是从0V开始上电的

大家可以看下&#xff0c;这张图片是测试XILINX 的FPGA 325T的上电时序图&#xff0c;其中绿色的线是FPGA 核心电源VCCINT 1.0V的波形&#xff0c;黄色的是BANK的电源2.5V的波形&#xff0c;蓝色的是辅助电源1.8V 的波形大家有没有发现这个时序图中黄色的波形&#xff0c;也就是…

Java之多线程详解

目录 一、线程简介 进程&#xff08;Process &#xff09;与 线程&#xff08;Thread&#xff09; 二、线程创建 1、线程Thread 1.1. 步骤 1.2 应用 1.3 案例&#xff1a;下载图片 2、实现Runnable接口 2.1 步骤 2.2 应用 3.小结 3. 实现Callable接口&#xff08;了解…

java开发的考研系统大学生考研推荐网站考研网站源码

简介&#xff1a; 考研信息推荐查询。主要是管理发布管理考研的知识文章&#xff0c;或者上传资料&#xff0c;发布考研的视频。学生可以注册后下载资料&#xff0c;查看考研文章视频等。文章分为vip文章和普通文章&#xff0c;学生查看vip文章需要消耗积分。 演示视频 https…

FX5U 原点回归指令 DSZR

上一篇文章中转述了网友的文章&#xff0c;因回原点实在重要&#xff0c;再详细描述DSZR指令。 DSZR是具有自动搜索功能的原点回归指令。它对当前位置没有要求&#xff0c;在任意位置哪怕是停止在限位开关位置上都能完成原点回归操作。 1.指令格式 S1 原点回归速度或存储了数…

linux虚拟机搭建kafka(单节点、使用kafka自带zookeeper)

本文使用kafka单节点安装及配置&#xff0c;并使用kafka自带的zookeeper。一般kafka需要起三个kafka构成集群&#xff0c;可以连单独的zookeeper&#xff0c;本文不涉及。一、kafka下载解压安装包下载地址&#xff1a;https://archive.apache.org/dist/kafka/2.5.0/kafka_2.12-…

MyPerf4J结合Grafana和InfluxDB采集JVM以及QPS指标

MyPerf4J结合Grafana和InfluxDB采集JVM以及QPS指标 背景 ​ 需要采集现场java程序运行的状态数据(包括JVM指标以及QPS,RPS指标等)。需要采集的方式尽可能轻量化 ​ 结合实际情况采用MyPerf4J作为Java探针&#xff0c;InfluxDB作为数据存储端&#xff0c;Grafana作为数据展示…

15---整合Echarts和完善头像上传

1、完善头像上传功能 上次写的头像上传功能&#xff0c;不能实现上传保存后立刻刷新右上角头像&#xff0c;这里做一个完善。首先是在Manage.vue中&#xff08;父&#xff09;&#xff0c;写刷新User的方法 //传一个user过去到header <Header :collapseBtnClass"col…

【信息论与编码 沈连丰】第三章:离散信源

【信息论与编码 沈连丰】第三章&#xff1a;离散信源第三章 离散信源3.1 离散信源的分类及其描述3.2 离散信源的熵3.3 信源的冗余度3.4 信源符号序列分组定理3.5 平稳离散信源及其性质第三章 离散信源 3.1 离散信源的分类及其描述 信源分类&#xff1a;本质上主要基于两方面来…

fastai教程学习笔记

这几天对着fastai教程读了下&#xff0c;大部分写得已经很不错。这里做点知识精炼的笔记。 安装fastai 推荐在conda环境内执行以下命令。它 pip install fastaifastai架构 fastai的编程架构如下图所示&#xff1a; fastai提供了高、中、低三层的API&#xff0c;用户可以根…

73、【哈希表】leetcode——15. 三数之和(C++版本)

题目描述 原题链接&#xff1a;15. 三数之和 解题思路 本题的难点在于去重&#xff0c;针对两种不同的方式&#xff1a;双指针和Hash采用不同的去重判定条件。 1、去重的目标 要明确&#xff0c;去重的是重复三元组&#xff0c;而不是三元组里重复的数。 2、去重初步思路 …

商业与数据生态议题解读,Doris Summit 2022 分论坛议程介绍|即刻报名

Doris Summit 2022 将于1 月 6 -7 日在线上正式举办&#xff0c;本次峰会共分2 天进行&#xff0c;首日上午为主论坛&#xff1a;核心技术解析&#xff0c;下午为商业与数据生态分论坛&#xff0c;7 日全天为行业用户最佳实践案例。大会汇聚了来自全球顶尖云厂商、一线互联网企…

CoMER论文翻译

文章目录Abstract1、Introduction2、Related Work2.1 HMER Methods2.2 Coverage Mechanism3、Methodology3.1、Background3.2、CNN Encoder3.3、Positional Encoding3.4、Attention Refinement Module3.5、Coverage4 Experiments论文链接&#xff1a;https://arxiv.org/abs/220…

数字图像处理 图像对比度增强算法概览

一、图像对比度增强 图像对比度增强又叫作图像对比度拉伸或者直接称为点运算。图像亮度和对比度调整的目的之一是在合适的亮度上提供最大的细节信息&#xff0c;细节纹理的沟纹越深&#xff0c;图像越清晰。在图像处理中&#xff0c;图像对比度增强是最基本的、原理比较简单却很…

【前端】Vuex模块化和持久化应用示例

概述 Vuex作为VUE状态管理组件&#xff0c;能够将项目公共数据进行统一管理。而且可以按照不同的业务功能将数据状态分模块管理。另外&#xff0c;对于网页刷新导致Vuex状态丢失的问题可以使用vuex-persistedstate插件配置将数据保存在localStorage或者sessionStorage中。 本…

「Python|场景案例」如何给图片添加水印

本文主要介绍如何使用python的PIL库给图片增加水印 文章目录背景说明工具准备处理步骤源代码处理效果展示背景说明 当我们想给一些图片添加水印的时候&#xff0c;尤其是图片数量较多的时候&#xff0c;就可以使用python进行自动化处理。包括但不限于在自媒体上发布自己的各种…

如何使用自助式商业智能 (BI) 避免组织中的数据孤岛

许多组织都存在数据问题。当许多员工远程工作&#xff08;或在混合环境中&#xff09;并在多个位置使用多个设备访问公司数据时&#xff0c;他们正在处理信息过载问题。这只会加剧数据孤岛的问题。 数据孤岛正是它听起来的样子&#xff1a;孤立在一个孤立的用户/环境中的数据&…

jdk版本和Class编译版本对应关系

JDK version和class file version(Class编译版本号)对应关系 JDK 17 61, JDK 16 60, JDK 15 59, JDK 14 58, JDK 13 57, JDK 12 56, JDK 11 55, JDK 10 54, JDK 9 53, JDK 8 52, JDK 7 51, JDK 6.0 50, JDK 5.0 …

数据结构-归并排序

一、概念及其介绍 归并排序&#xff08;Merge sort&#xff09;是建立在归并操作上的一种有效、稳定的排序算法&#xff0c;该算法是采用分治法(Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每…

三年“云改”,移动云这份答卷有多“硬”?

作者 | 曾响铃 文 | 响铃说 云计算是推动数字经济与实体经济深度融合的催化剂&#xff0c;是重点领域数字产业发展的助推器。近年来我国云计算产业发展提速&#xff0c;加快推动实体企业转型升级和创新发展。 2022年是移动云实施“云改”战略的第3年&#xff0c;也是移动云全…