动态规划-基础(斐波那契数、爬楼梯、使用最小花费爬楼梯、不同路径、不同路径II、整数拆分、不同的二叉搜索树)

动态规划,英文:Dynamic Programming,简称 DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。所以动态规划中每一个状态一定是由上一个状态推导出来的。
动态规划问题,五步走:
状态定义:确定 dp 数组,下标及其含义
状态转移:
初始化:
遍历顺序:
返回值:
动态规划代码有问题分析
举例推导状态转移公式
打印 dp 数组日志

1.斐波那契数

题目链接:509. 斐波那契数 - 力扣(LeetCode)

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1

F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定 n ,请计算 F(n) 。

示例 1:

输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1

示例 2:

输入:n = 3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2

示例 3:

输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3

提示:

0 <= n <= 30

代码:

    /**
    1. 状态定义:dp[i]为斐波那契数列的自变量i,dp[i] = F(i)
    2. 状态转移:dp[i] = dp[i-1] + dp[i-2]
    3. 初始化:dp[0] = 0, dp[1] = 1
    4. 遍历顺序:正序
    5. 返回形式:dp[n]
     */
    public int fib(int n) {
        if(n == 0 || n == 1) {
            return n;
        }
        int a = 0, b = 1,sum = 0;
        for(int i = 2; i <= n; i++) {
            sum = a + b;
            a = b;
            b = sum;
        }
        return sum;
    }

2. 爬楼梯

题目链接:70. 爬楼梯 - 力扣(LeetCode)

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1 阶 + 1 阶
2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1 阶 + 1 阶 + 1 阶
1 阶 + 2 阶
2 阶 + 1 阶

提示:

1 <= n <= 45

思路:

代码:

    /**
    1. 状态定义:到达第 i 个台阶,有 dp[i] 中方法
    2. 状态转移:dp[i] = dp[i-1] + dp[i-2]
    3. 初始化:dp[1] = 1 dp[2] = 2  注意题中要求 n != 0
    4. 遍历顺序:从前往后
    5. 返回值:返回 dp[n]
     */
    public int climbStairs(int n) {
        if(n < 2) return n;
        int[] dp = new int[n+1];
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3; i <= n; i++) {
            dp[i] = dp[i-2] + dp[i-1];
        }
        return dp[n];
    }

3. 使用最小花费爬楼梯

题目链接:使用最小花费爬楼梯

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

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

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

示例 1:

输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
支付 15 ,向上爬两个台阶,到达楼梯顶部。
总花费为 15 。

示例 2:

输入:cost = [1,100,1,1,1,100,1,1,100,1]
输出:6
解释:你将从下标为 0 的台阶开始。
支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。

提示:

2 <= cost.length <= 1000

0 <= cost[i] <= 999

思路:

代码:

    /**
    1. 状态定义:到达 i 位置最小花费 dp[i]
    2. 状态转移:dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])
    3. 初始化:dp[0] = 0, dp[1] = 0 前两个台阶是直接到达的,不花费
    4. 遍历顺序:从前往后
    5. 返回值:dp[cost.length]
     */
    public int minCostClimbingStairs(int[] cost) {
        int len = cost.length;
        int[] dp = new int[len + 1];
        dp[0] = 0;
        dp[1] = 0;
        for(int i = 2; i <= len; i++) {
            dp[i] = Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }
        return dp[len];
    }

4. 不同路径

题目链接:62. 不同路径 - 力扣(LeetCode)

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

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

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

示例 1:

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

示例 2:

输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
向右 -> 向下 -> 向下
向下 -> 向下 -> 向右
向下 -> 向右 -> 向下

示例 3:

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

示例 4:

输入:m = 3, n = 3
输出:6

提示:

1 <= m, n <= 100

题目数据保证答案小于等于 2 * 109

思路:

代码:

/**
 1. 状态定义:dp[i][j] 表示从 (0,0) 到 ()
 2. 状态转移:dp[i][j] = dp[i-1][j] + dp[i][j-1]
 3. 初始化: 行:dp[0][j] = 1, 列:dp[i][0] = 1
 4. 遍历顺序:从左到右,从上到下
 5. 返回值:dp[m][n]
 */
public int uniquePaths(int m, int n) {
    int[][] dp = new int[m][n];
    // 初始化
    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];
}

5. 不同路径 II

题目链接:63. 不同路径 II - 力扣(LeetCode)

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

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

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

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

示例 1:

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

示例 2:

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

提示:

  • m == obstacleGrid.length

  • n == obstacleGrid[i].length

  • 1 <= m, n <= 100

  • obstacleGrid[i][j] 为 0 或 1

思路:

代码:

    /**
    1. 状态定义: dp[i][j] 表示到达 (i,j) 位置有多少种走法
    2. 状态转移:条件:obs[i][j] = 0 时才有这个方程,表示这个位置没有障碍物
    dp[i][j] = dp[i-1][j] + dp[i][j-1]   
    3. 初始化:条件:当 obs[i][0] = 0 时,才有 dp[i][0] = 1
                    当 obs[0][j] = 0 时,才有 dp[0][j] = 1  
    4. 遍历顺序:从上到下,从左到右
    5. 返回值:当初始位置或结束位置 obs 为 1 时,表示有障碍,直接返回 0,正常情况下返回 dp[m][n]
     */
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length; // 行
        int n = obstacleGrid[0].length; // 列
        if(obstacleGrid[0][0] == 1 || obstacleGrid[m-1][n-1] == 1) {
            return 0;
        }
        int[][] dp = new int[m][n];
        // 初始化
        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] == 0) {
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }
        return dp[m-1][n-1];
    }

6. 整数拆分

题目链接:343. 整数拆分 - 力扣(LeetCode)

给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k >= 2 ),并使这些整数的乘积最大化。

返回 你可以获得的最大乘积 。

示例 1:

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

示例 2:

输入: n = 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

提示:

2 <= n <= 58

思路:

代码:

    /**
    1. 状态定义:对 i 进行拆分,得到最大的积为 dp[i]
    2. 状态转移:dp[i] = Math.max(dp[i], Math.max(j*(i-j), j * dp[i-j]));
    3. 初始化:dp[0] = 0,dp[1] = 0,dp[2] = 2
    4. 遍历顺序:从前向后
    5. 返回值:dp[n]
     */
    public int integerBreak(int n) {
        int[] dp = new int[n+1];
        dp[2] = 1;
        for(int i = 3; i <= n; i++) {
            for(int j = 1; j <= i-j; j++) {
                dp[i] = Math.max(dp[i],Math.max(j*(i-j), j*dp[i-j]));
            }
        }
        return dp[n];
    }

7. 不同的二叉搜索树

题目链接:96. 不同的二叉搜索树 - 力扣(LeetCode)

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入:n = 3

输出:5

示例 2:

输入:n = 1

输出:1

提示:

1 <= n <= 19

思路:

代码:

/**
 1. 状态定义:dp[i] 表示输入 i,有 dp[i] 种不同的二叉搜索树
 2. 状态转移:dp[i] += dp[j-1]*dp[i-j]
 3. 初始化:dp[0] = 1, dp[1] = 1
 4. 遍历顺序:从小到大
 5. 返回值:dp[n]
*/
public int numTrees(int n) {
 int[] dp = new int[n+1];
 dp[0] = 1;
 dp[1] = 1;
 for(int i = 2; i <= n; i++) {
     for(int j = 1; j <= i; j++) {
         dp[i] += dp[j-1]*dp[i-j];
     }
 }
 return dp[n];
}2. 背包问题

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】双向链表

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a; 初阶数据结构 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是…

海思SD3403/SS928V100开发(7)mcp2515-SPI转CAN驱动开发

1. 前言 需求: 需要一路can进行收发 分析: 根据目前使用较多的方案是使用主控端SPI接口 接入MCP2515芯片进行CAN协议转换 硬件: MCP2515->SPI2->SS928 2. Uboot开发 2.1 pinmux复用配置 2.1.1 修改uboot参数表 路径: osdrv/tools/pc/uboot_tools/ SS928V100…

Android 进程间通信机制(三) 系统进程与应用进程通信

一. 概述 Android中有一个重要的系统进程(system_server)&#xff0c;运行着系统中非常重要服务(AMS, PMS, WMS等)&#xff0c; 针对Activity而言&#xff0c;系统进程需要不断地调度Activity执行&#xff0c;管理Activity的状态; 每一个APK都需要运行在一个应用进程中&#xf…

【动态规划】最长上升子序列(单调队列、贪心优化)

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

jvm-题库

1、JVM内存模型 JVM内存区域总共分为两种类型 线程私有区域&#xff1a;程序计数器、本地方法栈和虚拟机栈 线程共享区域&#xff1a;堆&#xff08;heap&#xff09;和方法区 特征 线程私有区域&#xff1a;依赖用户的线程创建而创建、销毁而销毁&#xff0c;因用户每次访问都…

带头双向循环链表

在前面我们学习了单链表&#xff0c;发现单链表还是有一些不够方便&#xff0c;比如我们要尾插&#xff0c;需要遍历一遍然后找到它的尾&#xff0c;这样时间复炸度就为O(N),现在我们引入双向带头链表就很方便了&#xff0c;我们先看看它的结构。通过观察&#xff0c;我们发现一…

Vue全新一代状态管理库 Pinia【一篇通】

文章目录前言1. Pinia 是什么&#xff1f;1.1 为什么取名叫 Pinia?1.2. 为什么要使用 Pinia ?2. 安装 Pinia2.1.创建 Store2.1.1. Option 类型 Store2.1.2 Setup 函数类型 Store2.1.3 模板中使用3. State 的使用事项&#xff08;Option Store &#xff09;3.1 读取 State3.2 …

EEPROM芯片(24c02)使用详解(I2C通信时序分析、操作源码分析、原理图分析)

1、前言 (1)本文主要是通过24c02芯片来讲解I2C接口的EEPROM操作方法&#xff0c;包含底层时序和读写的代码&#xff1b; (2)大部分代码是EEPROM芯片通用的&#xff0c;但是其中关于某些时间的要求&#xff0c;是和具体芯片相关的&#xff0c;和主控芯片和外设芯片都有关系&…

一天吃透TCP面试八股文

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

vue模板语法

src目录文件说明&#xff1a; 1&#xff0c;数据绑定{{}} 数据绑定最常见的形式就是使用{{}}&#xff08;双花括号&#xff09;语法的文本插值 在template中使用{{}}文本插值语法中&#xff0c;设置一个变量&#xff0c;再在script中引入data函数&#xff0c;在return中进行数…

接口测试和性能测试有什么区别?我敢打赌你一定不知道

目录 一、什么是接口测试 二、接口测试原理 三、接口测试步骤 四、什么是性能测试 五、性能测试步骤 六、接口测试和性能测试的区别 一、什么是接口测试 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点…

2023最全Python+Selenium环境搭建教程-你绝对想不到有这么简单!

还有视频版本结合项目实战介绍&#xff0c;轻松学习&#xff01; PythonSelenium自动化测试环境搭建Web自动化测试全套教程_哔哩哔哩_bilibiliPythonSelenium自动化测试环境搭建Web自动化测试全套教程共计180条视频&#xff0c;包括&#xff1a;1、Web自动化测试需求和挑战、2…

深度学习-Tensorflow使用Keras进行模型训练

本文以FasionMNIST/加州房价数据集为例&#xff0c;介绍KerasAPI进行分类问题/回归问题模型训练的方法Tensorflow版本Tensorflow和keara都需要2.0及以上版本import tensorflow as tf from tensorflow import keras print(tf.__version__) print(keras.__version__)分类MLP构建数…

AI_Papers周刊:第六期

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 2023.03.13—2023.03.19 文摘词云 Top Papers Subjects: cs.CL 1.UPRISE: Universal Prompt Retrieval for Improving Zero-Shot Evaluation 标题&#xff1a;UPRISE&#xff1a;改进零样本评估…

要是早看到这篇文章,你起码少走3年弯路,20年老程序员的忠告

文章目录前言一、程序员的薪资是怎么样的&#xff1f;二、我现在的情况适合做程序员吗&#xff1f;三、大学期间到底应该学些什么&#xff1f;四、工作还是考研&#xff1f;五、总结前言 我是龙叔&#xff0c;一名工作了20多年的退休老程序员。 如果你在工作之前看到这篇文章…

【AI大比拼】文心一言 VS ChatGPT-4

摘要&#xff1a;本文将对比分析两款知名的 AI 对话引擎&#xff1a;文心一言和 OpenAI 的 ChatGPT&#xff0c;通过实际案例让大家对这两款对话引擎有更深入的了解&#xff0c;以便大家选择合适的 AI 对话引擎。 亲爱的 CSDN 朋友们&#xff0c;大家好&#xff01;近年来&…

libcurl库访问人工智能平台之人脸识别

一、前言上一篇文章我们调用libcurl库去访问了百度&#xff0c;访问的是http协议的百度云主页。那么现在我们要基于翔云人工智能平台来实现人脸识别&#xff0c;具体的操作大概就是我们在linux下调用libcurl库去访问翔云人工智能平台&#xff0c;然后实现我们想要的两张人脸图片…

FPGA纯verilog实现RIFFA的PCIE通信,提供工程源码和软件驱动

目录1、前言2、RIFFA简介RIFFA概述RIFFA架构RIFFA驱动3、vivado工程详解4、上板调试验证并演示5、福利&#xff1a;工程代码的获取1、前言 PCIE是目前速率很高的外部板卡与CPU通信的方案之一&#xff0c;广泛应用于电脑主板与外部板卡的通讯&#xff0c;PCIE协议极其复杂&…

【Linux】基本指令介绍

前言从今天开始&#xff0c;我们一起来学习Linux的相关知识&#xff0c;今天先来介绍怎么登录Linux&#xff0c;并且介绍一些Linux的基本指令。使用 XShell 远程登录 Linux很多同学的 Linux 启动进入图形化的桌面. 这个东西大家以后就可以忘记了. 以后的工作中 没有机会 使用图…

蓝桥杯刷题冲刺 | 倒计时21天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.迷宫1.迷宫 题目 链接&#xff1a; 迷宫 - 蓝桥云课 (lanqiao.cn) 本题为填空题&#xff0c;只…