动态规划入门学习(322. 零钱兑换、62. 不同路径、55. 跳跃游戏)

322. 零钱兑换

题目链接:https://leetcode-cn.com/problems/coin-change
难度:中等

1.题目

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

2.示例

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

3.题解

思路:目标是求最少的硬币数量,设f[i]为总金额是i时的最少硬币数量。
对函数最后一步的分析得到 f[i] = min{ f[ i - coins[j] ],f[i] }, coins[j]表示任意一种面额的硬币。

class Solution {
    public int coinChange(int[] coins, int amount) {
        //创建一个包含1--amount的数组
        int[] f = new int[amount+1];
        int n = coins.length;
        //初始值总金额为0元只需要0张纸币
        f[0] = 0;
        
		//循环求出f[i]的值
        for(int i=1;i<=amount;i++){
        	//规定当f[i] = Integer.MAX_VALUE时 没有任何一种硬币组合能组成总金额
            f[i] = Integer.MAX_VALUE;
            //循环遍历硬币的面额
            for(int j=0;j<n;j++){
           		//只有当总金额不小于纸币面额,
           		//且对于任意时刻,总面额减去某一纸币面额后的子面额,
           		//仍存在有最优的硬币组合时,此时的总面额才有可行的硬币组合
                if(i>=coins[j]&&f[i-coins[j]]!=Integer.MAX_VALUE){
                    f[i] = Math.min(f[i-coins[j]]+1,f[i]);
                }
            }
        }
        return f[amount]==Integer.MAX_VALUE?-1:f[amount];
    }
}

复杂度分析
时间复杂度:O(Sn)
空间复杂度:O(S)
S表示金额数,n表示面额数

62. 不同路径

题目链接:https://leetcode-cn.com/problems/unique-paths
难度:中等

1.题目

一个机器人位于一个 m x n 网格的左上角机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。问总共有多少条不同的路径

2.示例

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

3.题解

思路:设f(i,j)表示机器人走到(i,j)时的路径数量。0<i<m,0<j<n。
对于在(i,j)的函数有f(i,j)=f(i-1,j)+f(i,j-1)恒成立。
对于在i=0和j=0的情况下的任意点,f函数的数值都为1。

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] f = new int[m][n];
        for(int i=0;i<m;i++){
            f[i][0] = 1;
        }
        for(int i=1;i<n;i++){
            f[0][i] = 1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                f[i][j] = f[i-1][j]+f[i][j-1];
            }
        }
        return f[m-1][n-1];
    }
}

复杂度分析
时间复杂度:O(nm)
空间复杂度:O(nm)

55. 跳跃游戏

题目链接:https://leetcode-cn.com/problems/jump-game
难度:中等

1.题目

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。

2.示例

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 13 步到达最后一个下标。

3.题解

思路:设函数f[i]表示在下标为i时,你是否有可能站在这个位置上,如果可能就为true,否则为false。
要使f[i]为true,则对于f[i]之前的任意一个数j需要满足j+nums[j],即在f[j]位置上能移动到的距离大于i。
初始状态f[0]为初始位置必定为true。

class Solution {
    public boolean canJump(int[] nums) {
        int n = nums.length;
        boolean[] f = new boolean[n];
        f[0] = true;
        for(int i=1;i<n;i++){
            f[i] = false;
            for(int j=0;j<i;j++){
            	//对于值为true的前值进行判断,若可以到达f[i]位置,则设f[i]为true,并跳出该循环
                 if(f[j] && j+nums[j] >= i){
                     f[i] = true;
                     break;
                 }
            }
        }
        return f[n-1];
    }
}

复杂度分析
时间复杂度:O(n2)
空间复杂度:O(n)

动态规划入门学习-问题总结

先确定需要求得的最后一步由什么得到。将最终问题转换成其子问题(如零钱兑换中的示例最后一步获得的硬币a,那么对应的子问题就可以是amount-k),从而确定转移方程。之后考虑初始条件和边界情况,最后编码实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值