动态规划day2345【代码随想录学习】
创始人
2025-05-29 19:53:21
0

动态规划五部曲

  • 1、确定dp数组以及下标含义
  • 2、确定递推公式---->状态转移方程
  • 3、dp数组如何初始化
  • 4、确定遍历顺序
  • 5、举例推导dp数组(如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。)
int fib(int n){    if (n <= 1){        return n;   }    vector dp(n+1);    dp[0] = 0;    dp[1] = 1;    for (int i = 2; i <= n; ++i) {        dp[i] = dp[i - 1] + dp[i - 2];    }    return dp[n];
}

使用最小花费爬楼梯

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

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

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

img

1、确定dp数组以及下标含义:

dp[i]:到达第i台阶所花费的最少力气为dp[i]

2、确定递推公式

dp[i] = min(dp[i-1] +cost[i-1],dp[i-2]+cost[i-2]);

3、dp数组初始化

dp[0]=0;

dp[1]=0;

4、确定遍历顺序

顺序遍历

5、举例推导dp数组

int minCostClimbingStairs(vector& cost){    vector dp(cost.size()+1);    dp[0] = 0;    dp[1] = 0;    for (int i = 2; i <= cost.size(); ++i) {       dp[i] = min(dp[i - 1] + cost[i -1],dp[i - 2] +  cost[i - 2]);    }    return dp[cost.size()];}
int main(){    vector cost = {1,100,1,1,1,100,1,1,100,1};    				cout<

如果代码写出来了,一直AC不了,灵魂三问:

  1. 这道题目我举例推导状态转移公式了么?
  2. 我打印dp数组的日志了么?
  3. 打印出来了dp数组和我想的一样么?

不同路径 力扣题目链接

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?img

  • 输入:m = 3, n = 7
  • 输出:28

示例 2:

  • 输入:m = 2, n = 3
  • 输出:3

解释: 从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向右 -> 向下
  2. 向右 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向右
int uniquePaths(int m,int n){vector> dp(m,vector(n,0));//定义一个m*n二维数组,所有元素置为0;    //初始化    for (int i = 0; i < m; ++i) dp[i][0] = 1;    for (int j = 0; j < n; ++j) dp[0][j] = 1;    for (int i = 1; i < m; ++i) {        for (int j = 1; j < n; ++j) {           dp[i][j] = dp[i-1][j] + dp[i][j-1];//状态转移公式      }    }return dp[m-1][n-1];
}

不同路径Ⅱ 力扣题目链接

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?img

网格中的障碍物和空位置分别用 1 和 0 来表示。

示例 1:img

  • 输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
  • 输出:2 解释:
  • 3x3 网格的正中间有一个障碍物。
  • 从左上角到右下角一共有 2 条不同的路径:
    1. 向右 -> 向右 -> 向下 -> 向下
    2. 向下 -> 向下 -> 向右 -> 向右

示例 2: img

  • 输入:obstacleGrid = [[0,1],[0,0]]
  • 输出:1

提示:

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j] 为 0 或 1
int uniquePathsWithObstacles(vector>& obstacleGrid) {    int m = obstacleGrid.size();    int n = obstacleGrid[0].size();    if (obstacleGrid[m-1][n-1] == 1 || obstacleGrid[0][0] == 1){        return 0;
//            cout<<"no";    
}    vector> dp(m,vector(n,0));    for (int i = 0; i < m && obstacleGrid[i][0] == 0; ++i) dp[i][0] = 1;   for (int j = 0; j < n && obstacleGrid[0][j] == 0; ++j) dp[0][j] = 1;   for (int i = 1; i < m; ++i) {        for (int j = 1; j < n; ++j) {            if (obstacleGrid[i][j] == 1) continue;           dp[i][j] = dp[i-1][j] + dp[i][j-1];        }    }   /* for (int i = 0; i < m; ++i) {        for (int j = 0; j < n; ++j) {            						cout<

整数拆分 力扣题目链接

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

示例 1:

  • 输入: 2
  • 输出: 1
  • 解释: 2 = 1 + 1, 1 × 1 = 1。

示例 2:

  • 输入: 10
  • 输出: 36
  • 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
  • 说明: 你可以假设 n 不小于 2 且不大于 58。

动规五部曲,分析如下:

  • 1、确定dp数组(dp table)以及下标的含义

    dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。

  • 2、确定递推公式

​ 可以想 dp[i]最大乘积是怎么得到的呢?其实可以从1遍历j,然后有两种渠道得到dp[i].

一个是j * (i - j) 直接相乘。

一个是j * dp[i - j],相当于是拆分(i - j)。

j怎么就不拆分呢?

​ j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。

​ 递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

​ 也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。

​ 如果定义dp[i - j] * dp[j] 也是默认将一个数强制拆成4份以及4份以上了。

​ 所以递推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});

​ 那么在取最大值的时候,为什么还要比较dp[i]呢?

​ 因为在递推公式推导的过程中,每次计算dp[i],取最大的而已。

  • 3、dp的初始化

    严格从dp[i]的定义来说,dp[0] dp[1] 就不应该初始化,也就是没有意义的数值。

    拆分0和拆分1的最大乘积是多少?这是无解的。

    ​ 这里我只初始化dp[2] = 1,从dp[i]的定义来说,拆分数字2,得到的最大乘积是1,这个没有任何异议!

  • 4、确定遍历顺序

    确定遍历顺序,先来看看递归公式:

    dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));

    dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历,先有dp[i - j]再有dp[i]。

  • 5、举例推导dp数组

    举例当n为10 的时候,dp数组里的数值,如下:343.整数拆分

class Solution {
public:int integerBreak(int n) {vector dp(n + 1);dp[2] = 1;for (int i = 3; i <= n ; i++) {for (int j = 1; j <= i / 2; j++) {dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));}}return dp[n];}
};

相关内容

热门资讯

安卓只恢复系统应用,重拾系统流... 你有没有遇到过这种情况?手机突然卡顿,或者某个应用突然罢工,你一气之下,直接开启了“恢复出厂设置”大...
安卓系统出现支付漏洞,揭秘潜在... 你知道吗?最近安卓系统可是闹出了不小的风波呢!没错,就是那个我们每天离不开的安卓系统,竟然出现了支付...
苹果换了安卓系统恢复,体验变革... 你有没有遇到过这种情况?手机里的苹果突然变成了安卓系统,而且还是那种让你摸不着头脑的恢复模式。别急,...
安卓怎么卸载系统app,轻松告... 手机里的系统应用越来越多,有时候真的让人眼花缭乱。有些应用虽然看起来很实用,但用起来却发现并不适合自...
安卓系统查看步数,揭秘日常运动... 你有没有发现,每天手机里的小秘密越来越多?今天,咱们就来聊聊安卓系统里那个悄悄记录你每一步的小家伙—...
安卓系统未来会不会,未知。 你有没有想过,那个陪伴我们手机生活的安卓系统,它的未来会怎样呢?想象每天早上醒来,手机屏幕上跳出的信...
安卓系统怎么设置截图,轻松捕捉... 亲爱的手机控们,你是不是也和我一样,有时候想记录下手机屏幕上的精彩瞬间呢?别急,今天就来手把手教你如...
安卓系统下载软件安装,安卓系统... 你有没有发现,手机里的安卓系统就像一个巨大的宝藏库,里面藏着各种各样的软件,让人眼花缭乱。今天,就让...
安卓10系统转移程序,轻松实现... 你有没有想过,当你从一台安卓手机升级到安卓10系统后,那些珍贵的照片、联系人、应用和数据怎么才能无缝...
安卓电脑强制重启系统,原因解析... 你有没有遇到过这种情况?你的安卓电脑突然间就强制重启了,屏幕上闪过一行行代码,你还没来得及保存文件,...
安卓怎么降低系统耗电,深度解析... 手机电量总是不够用,是不是你也和我一样,每天都要担心手机没电呢?别急,今天就来教你怎么给安卓手机降耗...
安卓系统的总体框架,架构与核心... 你有没有想过,你的手机里那个神奇的安卓系统,它到底是怎么运作的呢?今天,就让我带你一探究竟,揭开安卓...
谁的安卓系统好,谁家的安卓系统... 说到安卓系统,这可是个热门话题呢!你有没有想过,这么多安卓手机品牌,哪个的操作系统最让你心动?今天,...
安卓系统信付通,安全无忧的移动... 你知道吗?在安卓手机的世界里,有一个超级好用的支付工具,它就是信付通。今天,就让我带你来全方位了解一...
小米官方系统安卓包,深度解析与... 亲爱的数码爱好者们,你是否曾为手机系统而烦恼?市面上那么多手机品牌,各种操作系统让人眼花缭乱。今天,...
自制安卓手机双系统,自制安卓手... 你有没有想过,自己的手机可以同时运行两个操作系统呢?没错,就是那种安卓手机双系统!听起来是不是很酷?...
小米安卓系统怎么设置,科技前沿... 小米手机的用户们,是不是觉得安卓系统有点复杂,设置起来有点头疼呢?别担心,今天就来手把手教你如何轻松...
点歌系统支持安卓系统么,安卓用... 你有没有想过,在手机上点歌听歌,是不是也能像在KTV里那样随心所欲呢?现在,就让我来告诉你一个超级酷...
原版安卓系统刷机,解锁无限可能 你有没有想过,你的安卓手机其实可以焕然一新?没错,就是那种原汁原味的安卓系统,让你的手机重新找回当初...
欧尚改装安卓系统,打造智能驾驶... 你有没有想过,你的欧尚汽车其实也可以变身成为智能座驾呢?没错,就是那个你每天上下班的伙伴——欧尚,现...