首页 > 编程语言 >动态规划算法基础及leetcode例题

动态规划算法基础及leetcode例题

时间:2023-05-17 21:48:15浏览次数:50  
标签:背包 target nums int 算法 遍历 例题 leetcode dp

01 基础理论

题型:动规基础(斐波那契数列or爬楼梯);背包问题;打家劫舍;股票问题;子序列问题

动规误区:只要看懂递推就ok(递推公式只是一部分)

解决动态规划应该要思考的几步:

  • 状态转移的DP数组以及下标的含义
  • 递推公式
  • DP数组为何初始化
  • 遍历顺序
  • 打印DP数组

02 例题

基础题目

509.斐波那契数列

思路:

确定dp[i]含义:第i个斐波那契数值
递推公式:dp[i]=dp[i-1]+dp[i-2]
dp数组如何初始化:dp[0]=1,dp[1]=1
遍历顺序:从前向后
打印dp数组:为了debug,如果出错,打印检查输出数组;

java代码:

class Solution {
    public int fib(int n) {
        if (n <= 1) return n;             
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = 1;
        for (int index = 2; index <= n; index++){
            dp[index] = dp[index - 1] + dp[index - 2];
        }
        return dp[n];
    }
}

70. 爬楼梯

思路:

1阶 1种
2阶 2种
3阶 3种(1+2)【1阶的方法+2步就是3阶;2阶的方法+1步就到3阶】
4阶 5种(2+3)【2阶的方法+2步就是3阶;3阶的方法+1步就到3阶】
.....
找到了递推关系:依赖与前两个状态

java代码

class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

背包问题

01背包、完全背包、多重背包

01背包

二维dp实现01背包:

一维dp数组实现01背包:

416. 分割等和子集

思路:子集为所有元素之和的一半

容量为[所有元素之和的一半]的背包,抽象为01背包问题
dp[j]的含义:容量为j的背包,所背的最大价值
目标:dp[target]=target【每个元素的数组就是它的重量,也是它的价值】
递推公式:dp[j]=max(dp[j],dp(j-weight[i])+value[i]);
初始化:dp[0]=0;其他非零数组也等于0
遍历顺序:倒序【先物品,后背包】,因为每个元素只使用一次

java代码:

class Solution {
    public boolean canPartition(int[] nums) {
        if(nums == null || nums.length == 0) return false;
        int n = nums.length;
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        //总和为奇数,不能平分
        if(sum % 2 != 0) return false;
        int target = sum / 2;
        int[] dp = new int[target + 1];
        for(int i = 0; i < n; i++) {
            for(int j = target; j >= nums[i]; j--) {
                //物品 i 的重量是 nums[i],其价值也是 nums[i]
                dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);
            }
        }
        return dp[target] == target;
    }
}

完全背包

与0-1背包区别:数据可以重复使用
遍历顺序:正序遍历

正序遍历:

private static void testCompletePack(){
        int[] weight = {1, 3, 4};
        int[] value = {15, 20, 30};
        int bagWeight = 4;
        int[] dp = new int[bagWeight + 1];
        for (int i = 0; i < weight.length; i++){ // 遍历物品
            for (int j = weight[i]; j <= bagWeight; j++){ // 遍历背包容量
                dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
                System.out.print(j + "-" +dp[j]);
                System.out.print(" ");
            }
            System.out.println();
        }
}

//输出
1-15 2-30 3-45 4-60 
3-45 4-60 
4-60 

倒序遍历:

for (int i = 0; i < weight.length; i++){ // 遍历物品
    for (int j = bagWeight; j >= weight[i]; j--){ // 遍历背包容量
        dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
        System.out.print(j + "-" +dp[j]);
        System.out.print(" ");
     }
     System.out.println();
}

//输出
4-15 3-15 2-15 1-15 
4-35 3-20 
4-35 

518.零钱兑换II

动规五部曲:

dp含义:dp[j] 装满容量为j的背包,有dp[j]种方法【最终要求的:dp[amount]】
递推公式:dp[j]+=dp[j-coins[i]]//装满有多少种方法的递推公式
【dp[j]方法数与前面方法数相关(类似爬楼)】
初始化:dp[0]=1【装满背包为0的方法有一种】,非零下标初始为0
遍历顺序:先物品后背包(组合数);先背包后物品(排列数)

java代码:

class Solution {
    public int change(int amount, int[] coins) {
        //递推表达式
        int[] dp = new int[amount + 1];
        //初始化dp数组,表示金额为0时只有一种情况,也就是什么都不装
        dp[0] = 1;
        for (int i = 0; i < coins.length; i++) {
            for (int j = coins[i]; j <= amount; j++) {
                dp[j] += dp[j - coins[i]];
            }
        }
        return dp[amount];
    }
}

377. 组合总和 Ⅳ

与上一次不同的是:

遍历顺序:先背包后物品(求全排列的个数)

java代码

class Solution {
    public int combinationSum4(int[] nums, int target) {
        if(nums == null || nums.length==0) return 0;

        int[] dp = new int[target+1];
        dp[0] = 1;

        for(int j=0;j<=target;j++){
            for(int i=0;i<nums.length;i++){
                if(j>=nums[i]){
                    dp[j] += dp[j-nums[i]];
                }
            }
        }

        return dp[target];
    
    }
}

70. 爬楼梯

核心:排列数

java代码:

class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n+1];
        int[] nums = new int[]{1,2};

        dp[0]=1;

        for(int j = 0;j<=n;j++){
            for(int i=0;i<nums.length;i++){
                if(j>=nums[i]){
                    dp[j] += dp[j-nums[i]];
                }
            }
        }
        return dp[n];
    }
}

标签:背包,target,nums,int,算法,遍历,例题,leetcode,dp
From: https://www.cnblogs.com/yunshalee/p/17402952.html

相关文章

  • Paxos算法原理与推导
    Paxos算法在分布式领域具有非常重要的地位。但是Paxos算法有两个比较明显的缺点:1.难以理解2.工程实现更难。网上有很多讲解Paxos算法的文章,但是质量参差不齐。看了很多关于Paxos的资料后发现,学习Paxos最好的资料是论文《PaxosMadeSimple》,其次是中、英文版维基百科对Paxos的介......
  • 算法
    算法1排序1.1直接插入排序代码:voidinsertSort(intarr[],intn){inttemp,j;for(inti=1;i<n;i++){temp=arr[i];j=i-1;while(j>=0&&temp<arr[j]){arr[j+1]=arr[j];......
  • 无感FOC电机控制代码,算法采用滑膜观测器,SVPWM控制,启动采用Vf,全开源代码,很有参考价值
    无感FOC电机控制代码,算法采用滑膜观测器,SVPWM控制,启动采用Vf,全开源代码,很有参考价值。带原理图,SMO推导,附有相关的文档资料,matlab模型,电机控制资料。ID:858679491419183......
  • leetcode:二叉树的最大深度
    题目描述给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。示例:给定二叉树[3,9,20,null,null,15,7],3/\920/\157返回它的最大深度 3。题目链接:104.二叉树......
  • MATLAB仿真MIMO通信系统V-BALST结构ZF检测算 法与MMSE检测算法
    MATLAB仿真MIMO通信系统V-BALST结构ZF检测算法与MMSE检测算法商品形式:程序1、仿真V-BALST结构ZF检测算法性能,调制方式为QPSK2、仿真V-BALST结构MMSE检测算法性能,调制方式为QPSKID:4249643318184013......
  • 西门子Smart200 追剪算法程序送对应维纶屏监控程序 这算法是无级调速
    西门子Smart200追剪算法程序送对应维纶屏监控程序这算法是无级调速只是例程,一部PLC就能学习,需要使用理解后改变为自己需要的程序!只要一个PLC就可以运行,触摸屏直接用电脑模拟,如果接上步进伺服也可以直接运行ID:3110683180240276......
  • 神策杯 2018高校算法大师赛(个人、top2、top6)方案总结
    1竞赛背景神策数据推荐系统是基于神策分析平台的智能推荐系统。它针对客户需求和业务特点,并基于神策分析采集的用户行为数据使用机器学习算法来进行咨询、视频、商品等进行个性化推荐,为客户提供不同场景下的智能应用,如优化产品体验,提升点击率等核心的业务指标。神策推荐系统是一......
  • 山东算法赛网格事件智能分类topline
    赛题链接:http://data.sd.gov.cn/cmpt/cmptDetail.html?id=67baseline:https://aistudio.baidu.com/aistudio/projectdetail/3371314?contributionType=1分数:0.749+ 任务(1)赛题任务基于网格事件数据,对网格中的事件内容进行提取分析,对事件的类别进行划分,具体为根据提供的事件描述,......
  • Leetcode-Easy 806. Number of Lines To Write String
    题目描述给一个字符串S,从左到右将它们排列行,每行最大长度为100,,同时给定一个数组withds,widths[0]对应着a的宽度,widths[1]对应着b的宽度,...,widths[25]对应着z的宽度。求:至少需要多少行以及最后一行的长度下面是一个实例:Example:Input:widths=[10,10,10,10,10,10,1......
  • [每天例题]蓝桥杯 C语言 回文日期
    回文日期题目    思路分析1.由于题目要求是找到一定范围日期内的回文日期,所以我们可以采用for遍历日期2.再调用函数先判断闰年,再进行日期合法判断,最后再进行回文数判断3.注意,该日期范围包含起始和结束这两个日期,这里会有一个案例挖坑代码#include<stdio.h>int......