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, 然后再从下标 1 跳 3 步到达最后一个下标。
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),从而确定转移方程。之后考虑初始条件和边界情况,最后编码实现。