动态规划Day07

这篇具有很好参考价值的文章主要介绍了动态规划Day07。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

70. 爬楼梯(进阶版)

卡码网:57. 爬楼梯(opens new window)

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

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

输入描述:输入共一行,包含两个正整数,分别表示n, m

输出描述:输出一个整数,表示爬到楼顶的方法数。

输入示例:3 2

输出示例:3

提示:

当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。

此时你有三种方法可以爬到楼顶。

  • 1 阶 + 1 阶 + 1 阶段
  • 1 阶 + 2 阶
  • 2 阶 + 1 阶
看到题目的第一想法

        使用完全背包

        完全背包:同一个物品可以无限次使用

        背包 n   物品 0~m

        使用0~m 达到背包容量j 有多少种方法’

        这道题求的是顺序数,需要考虑背包和物品的顺序,应该是先背包后物品

看到代码随想录之后的想法

        动规五部曲,很快的写出解题思路

        1确定dp数组以及对应下标的含义

        使用0~m ,dp[j] 到达j层阶梯有多少种方法

        2确定递推公式

        dp[j]=dp[j-m]+dp[j]

        3dp数组初始化

        dp[0]=1 一切的起源

        4确定遍历顺序

        从前往后

        先背包后物品 因为需要考虑顺序

        5手动推导dp数组

        6打印dp数组

        

自己实现过程中遇到的困难

        求排列,我之前写成求组合了

        排列是要考虑顺序的,组合不需要考虑顺序

import java.util.*;
import java.lang.*;
 
public class Main{
    public static void main (String[] args) {
        /*
        本题看起来是一道简单题目,稍稍进阶一下其实就是一个完全背包!
 
如果我来面试的话,我就会先给候选人出一个 本题原题,看其表现,如果顺利写出来,进而在要求每次可以爬[1 - m]个台阶应该怎么写。
 
顺便再考察一下两个for循环的嵌套顺序,为什么target放外面,nums放里面。
 
这就能考察对背包问题本质的掌握程度,候选人是不是刷题背公式,一眼就看出来了。
 
这么一连套下来,如果候选人都能答出来,相信任何一位面试官都是非常满意的。
 
本题代码不长,题目也很普通,但稍稍一进阶就可以考察完全背包,而且题目进阶的内容在leetcode上并没有原题,一定程度上就可以排除掉刷题党了,简直是面试题目的绝佳选择!
        */
         //Dp数组的定义和每个下标的含义
         //完全背包,可以选择自己
         // weight[m]=[1,2,3...m]
         // j 代表到达j有多少种方法
         //dp[j] 爬到i层有多少中方法
         //确定递推公式
         // dp[j] += dp[j-nums[i]];
         //dp数组初始化
        // dp[0]=1
         //确定遍历顺序
         //从前往后,从nums[i]开始
         //举例推导dp数组
         Scanner sc = new Scanner(System.in);
         //n 为楼顶
         int n = sc.nextInt();
         // m 为一步最远的
         int m = sc.nextInt();
         int[] weight = new int[m+1];
         for(int i=1;i<=m;i++){
            weight[i] = i;
         }
         int dp[] = new int[n+1];
         dp[0]=1;
         // 这道题是求排列,所以我下面的顺序是错的,我这个顺序是求组合
         /*for(int i=1;i<=m;i++){
             for(int j=weight[i];j<=n;j++){
                 dp[j]+=dp[j-weight[i]];
             }
         }*/
         for(int j=1;j<=n;j++){
            for(int i=1;i<=m;i++){
                 if(j>=i) dp[j]+=dp[j-i];
             }
         }
         System.out.println(dp[n]);
    }
}

322. 零钱兑换(求最小值)

力扣题目链接(opens new window)

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。

示例 1:

  • 输入:coins = [1, 2, 5], amount = 11
  • 输出:3
  • 解释:11 = 5 + 5 + 1

示例 2:

  • 输入:coins = [2], amount = 3
  • 输出:-1

示例 3:

  • 输入:coins = [1], amount = 0
  • 输出:0

示例 4:

  • 输入:coins = [1], amount = 1
  • 输出:1

示例 5:

  • 输入:coins = [1], amount = 2
  • 输出:2

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 2^31 - 1
  • 0 <= amount <= 10^4
看到题目的第一想法

        可以凑成总金额所需的最少的硬币个数

        最小值应该怎么处理呢?没想到思路

看到代码随想录之后的想法

        动规五部曲,很快的写出解题思路

        1确定dp数组以及对应下标的含义

        使用0~m ,dp[j] 可以凑成总金额所需的最少的硬币个数

        2确定递推公式

        是否选中当前, 若选中则dp[j-coins[i]]+1

        dp[j]=Math.min(dp[j],dp[j-coins[i]]+1)

        3dp数组初始化

        dp[0]=0,其他都为Integer.MAX_VALUE

        4确定遍历顺序

        从前往后

        不需要考虑组合或排列,只是求最小值而已

        5手动推导dp数组

        6打印dp数组

        

自己实现过程中遇到的困难

        从dp[j]的定义来入手考虑递推公式,比如这道题dp[j]代表可以凑成总金额所需的最少的硬币个数,则递推公式为  ,要么选中当前物品 则为dp[j-coins[i]]+1 ,要么不选,则为dp[j](之前的值)

        求最小值,应该把其他元素都设为Integer.MAX_VALUE ,第一个元素为0文章来源地址https://www.toymoban.com/news/detail-821210.html

class Solution {
    public int coinChange(int[] coins, int amount) {
        //每次取最小值?
        //dp[i] 代表凑成总金额所需的硬币数目
        // 比如nums[0]=1 amount = 100 凑成1 需要dp[0]+1 or dp[1] 中的最小值 
        // 则凑成100 需要 dp[99]+1 or dp[100] 的最小值 ,dp[100-1] = dp[99]
        // dp数组的定义和下标的含义
        // 可以凑成j金额的最少硬币个数
        // 确定递推公式
        // 0~i凑成j金额的个数 每凑成一个+1
        // dp[j] = Math.min(dp[j-coins[i]]+1,dp[j])
        // dp数组初始化
        // dp[0] = 0,由于是凑成最小个数,则除开第一个外,其他的都是max
        // 确定遍历顺序
        // 举例推导dp数组
        
        int[] dp = new int[amount+1];
        dp[0]=0;
        for(int i=1;i<=amount;i++){
            dp[i] = Integer.MAX_VALUE;
        }
        for(int i=0;i<coins.length;i++){
            for(int j=coins[i];j<=amount;j++){
                //记录次数,每次加1
                // 只有j-coins[i] 不为最大值时,才有交换的必要,不然会把Integer.MAX_VALUE+1,造成溢出
                if(dp[j-coins[i]]!=Integer.MAX_VALUE)
                dp[j] = Math.min(dp[j],dp[j-coins[i]]+1);
            }
        }
        
        return dp[amount]==Integer.MAX_VALUE?-1:dp[amount];
    }
}

完全平方数

力扣题目链接(opens new window)

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

示例 1:

  • 输入:n = 12
  • 输出:3
  • 解释:12 = 4 + 4 + 4

示例 2:

  • 输入:n = 13
  • 输出:2
  • 解释:13 = 4 + 9

提示:

        看到题目的第一想法

        和上一题感觉差不多,也是求最小数量

        但物品为  各个数的平方,1 4 9 16.。。 要怎么来遍历?

        其实是用for循环来控制

        看到代码随想录之后的想法

        动规五部曲,很快的写出解题思路

        1确定dp数组以及对应下标的含义

        dp[j] 和为j的完全平方数的最小数量

        2确定递推公式

        是否选中当前, 若选中则dp[j-coins[i]]+1

        dp[j]=Math.min(dp[j],dp[j-i]+1)

        3dp数组初始化

        dp[0]=0,其他都为Integer.MAX_VALUE

        4确定遍历顺序

        从前往后

        不需要考虑组合或排列,只是求最小值而已

        5手动推导dp数组

        6打印dp数组

        

自己实现过程中遇到的困难

       按照for循环来确立物品的范围

        先背包后物品

        for(int i=1;i<=n;i++){

                //物品的平方要<=i

               for(int j=1;j*j<=i;j++){

                }

        }

        先物品后背包

        for(int i=1;i*i<=n;i++){

                //物品的平方要<=i

               for(int j=1;j<=m;j++){

                }

        }

        求最小值,应该把其他元素都设为Integer.MAX_VALUE ,第一个元素为0

  • class Solution {
        public int numSquares(int n) {
            //完全平方数和为背包容量j
            // 在完全平方数中选取能满足完全平方数和为背包容量j的最小个数
            // dp数组的定义和下标的含义
            // dp[j]为能满足容量j所需的完全平方数的最小个数
            // 确定递推公式
            // dp[j]=Math.min(dp[j],dp[j-某个平方]+1);
            // dp数组初始化
            // dp[0]=0,其他都为最大值
            // 确定遍历顺序
            // 可以重复使用,则从前往后
            // 举例推导dp数组
            // 平方为1 dp[0]=0,dp[1]=1;dp[2]=2;dp[3]=3;dp[4]=4;
            // 平方为4 dp[0]=0,dp[1]=1;dp[2]=2;dp[3]=3;dp[4]=1;
            
            int[] dp  = new int[n+1];
            for(int i=0;i<=n;i++){
                dp[i]=Integer.MAX_VALUE;
            }
            dp[0] = 0;
            for(int i=1;i*i<=n;i++){
                for(int j=i*i;j<=n;j++){
                    dp[j] = Math.min(dp[j],dp[j-i*i]+1);
                }
            }
            return dp[n];
        }
    }

到了这里,关于动态规划Day07的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法记录 | Day38 动态规划

    对于动态规划问题,将拆解为如下五步曲 确定dp数组(dp table)以及下标的含义 确定递推公式 dp数组如何初始化 确定遍历顺序 举例推导dp数组 思路: 确定dp数组(dp table)以及下标的含义:dp[i]的定义为:第i个数的斐波那契数值是dp[i] 确定递推公式:状态转移方程 dp[i] = dp

    2023年04月22日
    浏览(44)
  • 算法记录 | Day55 动态规划

    思路: 1.确定dp数组(dp table)以及下标的含义: dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为 dp[i][j] 。 2.确定递推公式: if (s[i - 1] == t[j - 1]) t中找到了一个字符在s中也出现了, dp[i][j] = dp[i - 1][j - 1] + 1 if (s[i - 1] != t[j - 1]) 相当于t要

    2024年02月03日
    浏览(49)
  • 算法记录 | Day45 动态规划

    改为:一步一个台阶,两个台阶,三个台阶,…,直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢? 1阶,2阶,… m阶就是物品,楼顶就是背包。 每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶。 问跳到楼顶有几种方法其实就是问装满背包有几种方法。 此时大家

    2024年02月11日
    浏览(33)
  • 算法|Day40 动态规划9

    LeetCode 198- 打家劫舍 题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 题目描述 :你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统, 如果两间相邻的房屋在同一晚上

    2024年02月12日
    浏览(31)
  • 算法|Day46 动态规划14

    LeetCode 1143- 最长公共子序列 题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 题目描述 :给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串:它是由原

    2024年02月11日
    浏览(46)
  • 算法记录 | Day53 动态规划

    思路: 本题和动态规划:718. 最长重复子数组 (opens new window)区别在于这里不要求是连续的了,但要有相对顺序,即:“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。 1.确定dp数组(dp table)以及下标的含义 dp[i][j] :长度为[0, i - 1]的字符串text1与长度为[0,

    2024年02月03日
    浏览(50)
  • Day 42算法记录| 动态规划 08

    单词就是物品,字符串s就是背包 1.dp[0]背包啥也不要用装,true。 2. for循环,顺序很重要,所以先背包再物品 如果求组合数就是外层for循环遍历物品,内层for遍历背包 。 如果求排列数就是外层for遍历背包,内层for循环遍历物品 。 3.递归: 要么装包或者不装 添加链接描述 把

    2024年02月15日
    浏览(31)
  • Day36算法记录|动态规划 dp02

    步骤回顾: C语言版本写的很清楚 对应得Java版本视频解析 方法一: 动态规划 1 确定dp数组(dp table)以及下标的含义 dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。 2 . 确定递推公式 ,求dp[i][j],只能有两个方向来推导出来,即dp[i - 1][j] 和 dp[i][j - 1]。 3. dp数

    2024年02月12日
    浏览(52)
  • Day47 算法记录|动态规划14子序列

    这道题和718. 最长重复子数组的区别:这道题的 子序列可以不连续 这个视频讲解的很好 和上面一道题一摸一样 以绘制连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且直线不与任何其他连线(非水平线)相交。 讲解的很好的一个 d p [ i ] dp[i] d p [ i ] 表示包括下标i(以

    2024年02月15日
    浏览(37)
  • day55 算法训练|动态规划part15

    给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,\\\"ace\\\"是\\\"abcde\\\"的一个子序列,而\\\"aec\\\"不是)。 其实就是最长公共子序列的变种题:如果公共子序列长度等于

    2024年02月02日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包