动态规划算法

news/2024/10/23 7:22:11/

一、前言

动态规划是一种常用的算法,在算法领域十分重要,但对于新手来说,理解起来有一定的挑战性,这篇博客将明确步骤来一步一步讲解动态规划到底该如何理解与运用。

二、解析动态规划算法

1.特点

①把原来的问题分解成了【要点相同】的子问题(这个要点可以和后面讲的状态联系起来理解)

②所有问题都只需要解决一次(解决一次就是只需要由后面所说的状态转移方程解决即可)

前这两个特点可以看出,其实动态规划就是以对解答问题的每个步骤具化成状态,用通过状态与状态之间的递推关系写出的状态转移方程来解决实际问题的算法

③储存子问题的解(状态转移方程中往大问题转移一定需要子问题的解,所有需要将子问题的解储存起来)

2.要素

①状态的定义

②状态间的转移方程定义

③状态的初始化

(初始状态确定已知)

④返回结果

(返回的结果恰好完全符合题目要求)

3.用动态规划解题步骤

①根据题目所给条件,以及所问问题,初步判断是否具有动态规划的特点(可分治,可转移,可储存)

②对状态做出定义后判断当前状态可以由哪几种子状态通过哪几种方式(紧扣题目条件)得到,并以此为依据写出状态转移方程,并找全四个要素

③写代码

4.例题

题目

跳台阶扩展问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶(n为正整数)总共有多少种跳法

分析

所以要想跳到第n个台阶,我们可以从第1个台阶跳上来,也可以从第2个台阶跳上来……,很明显有小问题推大问题的情节
递推公式是
f(n)=f(n-1)+f(n-2)+……+f(2)+f(1);
同样如果我们想跳到第n-1个台阶,也可以列出下面这个公式
f(n-1)=f(n-2)+……+f(2)+f(1);
通过这两个公式我们可以得出
f(n)=2*f(n-1)
实际上他是个等比数列,base case当n等于1的时候结果为1,来看下代码

代码

class Solution {
public:int jumpFloorII(int number) {if(number==0||number==1){return number;}else{int ret=1;while(number>1){ret=ret*2;number--;}return ret;}}
};

题目

最大连续子数组和
输入一个整形数组(可能有正数和负数),求数组中连续子数组(最少有一个元素)的最大和。要求时间复杂度为O(n)

分析

先假设以索引i-1结束时为状态,那么这个状态下时最大和怎么推导索引i结束时最大和呢,逻辑思考后可以发现,真实的最大连续子数组和肯定以某个索引结束的,所以找到dp中最大值即可。填充dp时,如果dp[i-1] < 0,那么dp[i]直接等于第i个数nums[i],否则就是dp[i] = dp[i-1] + nums[i]。

代码

 int main () {int n = 0, temp = 0;cin >> n;vector<int>  nums, dp(n, 0);while (cin >> temp) nums.push_back(temp);dp[0] = nums[0];for (int i = 1; i < n; i++) {if (dp[i-1] < 0) dp[i] = nums[i];else dp[i] = dp[i-1] + nums[i];}cout << *max_element(dp.begin(), dp.end()) << endl;return 0;
}

题目

单词拆分
给定一个字符串和一个字符串数组,在字符串的任意位置拆分任意次后得到的字符串集合是否是给定字符串数组的子集。

分析

出发点:给定字符串s的每个字符i
最优解:对于每个i之前的字符序列,分为j(0<=j<=i)前面的序列和j后面的序列,求解i转化为求解j和i-j
状态d(i):i之前的字符序列分段后的字符串能不能在字典中找到
递推公式:d(i) = d(i)||(d(j)&sub(i-j)), 其中j=0~i

代码

#include
using namespace std;
class Solution {
public:bool wordBreak(string s, unordered_set &dict) {// 动态规划:1\. 每一个状态和前一个状态有关;2\. 最小子状态是可以求得的// 转移方程:f(i)表示s[0,i]可以分词,那么f(i) = f(j) && f(j+1, i); (0<=j<i)int len = s.length();vector dp(len+1, false);dp[0] = true;for (int i = 1; i <= len; ++i) {        // 注意终止条件,此处从1开始,终止条件应该为lenfor (int j = i-1; j >= 0; --j) {if (dp[j] && dict.find(s.substr(j, i-j)) != dict.end()) {dp[i] = true;break;}}}return dp[len];}
};

~感谢观看❥(^_-)


http://www.ppmy.cn/news/33708.html

相关文章

vue使用split()将字符串分割数组join()将数组转字符串reverse()将数组反转

1.split() 将字符串切割成数组 const str Hello Vue2 Vue3 console.log(str.split()) console.log(str.split()) console.log(str.split( )) console.log(str.split( , 2)) console.log(str.split( , 6))输出如下 1.split()不传参数默认整个字符串作为数组的一个元素&#xf…

Java Web 实战 15 - 计算机网络之网络编程套接字

文章目录一 . 网络编程中的基本概念1.1 网络编程1.2 客户端(client) / 服务器(server)1.3 请求(request) / 响应(response)1.4 客户端和服务器之间的交互数据1.4.1 一问一答1.4.2 多问一答1.4.3 一问多答1.4.4 多问多答二 . socket 套接字2.1 UDP 的 Socket API2.1.1 引子2.1.2…

嵌入式硬件电路设计的基本技巧

目录 1 分模块 2 标注关键参数 3 电阻/电容/电感/磁珠的注释 4 可维修性 5 BOM表归一化 6 电源和地的符号 7 测试点 8 网络标号 9 容错性/兼容性 10 NC、NF 11 版本变更 12 悬空引脚 13 可扩展性 14 防呆 15 信号的流向 16 PCB走线建议 17 不使用\表示取反 不…

web测试技术

一、Web 测试与传统测试的区别 相同之处 测试内容&#xff1a; 功能、性能、易用性、兼容性、安全性等 测试方法&#xff1a; 等价类边界值法、判定表法、状态迁移法&#xff0c;流程分析法、因果图法、错误猜测法等 测试手段&#xff1a; 人工测试、工具测试等不同之处 Web 测…

C++造轮子飙车现场之无锁、有锁环形队列实现

先看带锁的实现。 带锁版本 circular_queue.h // 头文件防卫 #ifndef CIRCULAR_QUEUE_H #define CIRCULAR_QUEUE_H#include <mutex> // 互斥量 #include <condition_variable> // 条件变量template <typename T> class CircularQueue { public:// 构造函数…

docker安装overleaf并升级texlive

20230321 0. 引言 之前在虚拟机安装了overleaf&#xff0c;应该是两年前的事情了&#xff0c;本来是想尝试一下overleaf更新了什么功能&#xff0c;但是没想到浪费了这么多时间。当时安装的还是2.5的版本&#xff0c;现在已经是3.5了。 在这个过程中&#xff0c;有几个地方需…

脱不下孔乙己的长衫,现代的年轻人该怎么办?

“如果我没读过书&#xff0c;我还可以做别的工作&#xff0c;可我偏偏读过书” “学历本该是我的敲门砖&#xff0c;却成了我脱不下的长衫。” 最近&#xff0c;“脱下孔乙己的长衫”在网上火了。在鲁迅的原著小说中&#xff0c;孔乙己属于知识阶级&#xff08;长衫客&#xf…

供水管网微观水力模型

国外在管网建模方面起步于20世纪60年代。20世纪80年代&#xff0c;随着计算机及相应技术的发展&#xff0c;遥测远传设备的应用进入了实用化阶段&#xff0c;国内已有很多供水企业实现了供水管网建模。给水管网系统建模&#xff0c;就是为仿真模拟管网系统动态实时运行情况建立…