算法通关村-----动态规划高频问题

最少硬币数问题

问题描述

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。你可以认为每种硬币的数量是无限的。详见leetcode322

问题分析

设f(n)为amount=n时使用的最少金币数。遍历coins数组,选择f(n-coins[i])(i=0,1,coins.length-1)的最小值,即为需要的最少硬币数,递归继续寻找f(n-coins[i])的最小值,初始时f(0)=0,如果一些总金额无法凑成时,可以使用amount+1填充数组。

代码实现

java 复制代码
public int coinChange(int[] coins, int amount) {
    int[] res = new int[amount+1];
    int max = amount+1;
    Arrays.fill(res,max);
    res[0] = 0;
    int[] temp = new int[coins.length];
    for(int i=1;i<amount+1;i++){
        for(int j=0;j<coins.length;j++){
            int leftAmount = i - coins[j];
            temp[j] = leftAmount>=0?res[leftAmount]+1:max;
        }
        int min = max;
        for(int j=0;j<coins.length;j++){
            min = Math.min(temp[j],min);
        }
        res[i]= min;
    }
    if(res[amount]==max){
        return -1;
    }
    return res[amount];
}

最长连续递增子序列

问题描述

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。详见leetcode674

问题分析

这道题,我们之前使用滑动窗口的方式也可以解决,使用动态规划解题时,对于连续递增子序列的最后一个元素nums[k],存在两种情况,第一种是最长连续递增子序列长度为1,连续递增子序列只包含一个元素nums[k],第二种是存在k-1,使得nums[k-1]<num[k],设f[k]为到下标k处的连续递增子序列长度,则,如果nums[k-1]>=nums[k],f[k]=1,否则f[k]=f[k-1]+1,初始值f[0]=1,

代码实现

滑动窗口实现

java 复制代码
public int findLengthOfLCIS(int[] nums) {     
 	if(nums.length==0||nums.length==1){
        return nums.length;
    }
    int res = 1;
    int count =1;
    for(int i=1;i<nums.length;i++){
        if(nums[i-1]>=nums[i]){
            count =1;
        }else{
            count++;
        }
        if(count>res){
            res = count;
        }
    }
    return res;   
}

动态规划实现

java 复制代码
public int findLengthOfLCIS(int[] nums) {
    int[] dp = new int[nums.length];
    Arrays.fill(dp,1);
    int max = 1;
    for(int i=1;i<nums.length;i++){
        if(nums[i]>nums[i-1]){
            dp[i] = dp[i-1]+1;
            max = Math.max(dp[i],max);
        }
    }
    return max;
}

最长递增子序列

问题描述

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。详见leetcode300

问题分析

这道题与上一题相似,只是不需要连续递增。对于最长递增子序列的最后一个元素nums[k],存在两种情况,第一种是最长连续递增子序列长度为1,连续递增子序列只包含一个元素nums[k],第二种是存在i,使得i<k,nums[i]<num[k],设f[k]为到下标k处的连续递增子序列长度,则f[k] = max{f[i]+1}(i是所有nums[i]<nums[k]的集合)

代码实现

java 复制代码
public int lengthOfLIS(int[] nums) {
    int[] dp = new int[nums.length];
    Arrays.fill(dp,1);
    for(int i=1;i<nums.length;i++){
        for(int j=i-1;j>=0;j--){
            if(nums[j]<nums[i]&&dp[j]+1>dp[i]){
                dp[i] = dp[j]+1;
            }
        }
    }
    int max = 1;
    for(int i=0;i<nums.length;i++){
        max = Math.max(max,dp[i]);
    }
    return max;
}

最少完全平方数

问题描述

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。详见leetcode279

问题分析

设f(n)表示和为 n 的完全平方数的最少数量 。则f(n)=min{f(n-jj)+1}(j是满足所有jj<=n的j的集合).初始时f(0) = 0.

代码实现

java 复制代码
public int numSquares(int n) {
    int[] f = new int[n+1];
    Arrays.fill(f,Integer.MAX_VALUE);
    f[0] = 0;
    for(int i=1;i<n+1;i++){
        for(int j=1;j*j<=i;j++){
            if(f[i-j*j]+1<f[i]){
                f[i] = f[i-j*j]+1;
            }
        }
    }
    return f[n];
}

跳跃游戏

问题描述

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。详见leetcode55

问题分析

设f(n)是一个boolean数组,为true表示可以跳到数组下标n处,为false表示无法跳到数组下标n处。f(n)为true的条件是f(i)为true,n-1-i<nums[i],初始时f(0)=true

java 复制代码
public boolean canJump(int[] nums) {
    boolean[] f = new boolean[nums.length];
    Arrays.fill(f,false);
    f[0] = true;
    for(int i=1;i<nums.length;i++){
        for(int j=0;j<i;j++){
            if(f[j]&&j+nums[j]>=i){
                f[i] = true;
                break;
            }
        }
    } 
    return f[nums.length-1];
}

总结

这部分动态规划问题需要我们你想推导,即如何由我们想要结果的前一个状态得到我们想要的结果(往往是最值,所以涉及从前面多个状态到当前状态的选择)。逆向推导得到状态转移方程f,确定初始条件,一步步填充dp数组,最终得到我们想要的结果并返回。

相关推荐
荒古前16 分钟前
龟兔赛跑 PTA
c语言·算法
Colinnian19 分钟前
Codeforces Round 994 (Div. 2)-D题
算法·动态规划
用户00993831430125 分钟前
代码随想录算法训练营第十三天 | 二叉树part01
数据结构·算法
shinelord明29 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
დ旧言~35 分钟前
专题八:背包问题
算法·leetcode·动态规划·推荐算法
_WndProc1 小时前
C++ 日志输出
开发语言·c++·算法
努力学习编程的伍大侠1 小时前
基础排序算法
数据结构·c++·算法
林辞忧1 小时前
动态规划<四> 回文串问题(含对应LeetcodeOJ题)
动态规划
XiaoLeisj2 小时前
【递归,搜索与回溯算法 & 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)
数据结构·算法·leetcode·决策树·深度优先·剪枝