1. 零钱兑换
class Solution {
public int coinChange(int[] coins, int amount) {
int n = coins.length;
int[] arr = new int[amount + 1];// 0..amount
// 定义初始条件
arr[0] = 0;
for(int i = 1; i <= amount; i++) {
// 求arr[i]
arr[i] = Integer.MAX_VALUE;
for(int j = 0; j < n; j++) {
if(i >= coins[j] && arr[i - coins[j]] != Integer.MAX_VALUE && arr[i - coins[j]] + 1 < arr[i]) {
arr[i] = arr[i - coins[j]] + 1;
}
}
}
if (arr[amount] == Integer.MAX_VALUE) {
return -1;
}else {
return arr[amount];
}
}
}
2. 不同路径-1
分析:
动态规划第一步:确定状态
a. 最后一步: 无论机器人最后是如何到达终点的,最后一步只有两种情况,那就是从左到右和从上到下。设目标位置为[m - 1][n -1],则是从[m-2][n-1]和[m - 1][n - 2]过来的。
b. 子问题,原问题是从[0][0]到[m-1][n-1]转化为有多少种方式从[0][0]走到[m-2][n-1]和有多少种方式从从[0][0]走到[m-1][n-2]
动态规划第二步:状态转移方程
f[i][j] = f[i - 1][j] + f[i][j - 1]
动态规划第三步:初始条件和边界条件
初始条件:f[0][0] = 1
边界条件:i = 0或者j = 0的时候,只能从一个方向过来f[0][j] =1 f[i][0] = 1
动态规划第四步:计算顺序
计算第0行
计算第1行
。。。
计算第m - 1行
答案就是f[m - 1][n -1]
class Solution {
public int uniquePaths(int m, int n) {
int[][] arr = new int[m][n];
arr[0][0] = 1;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if (i == 0 || j == 0) {
arr[i][j] = 1;
}else{
arr[i][j] = arr[i][j - 1] + arr[i - 1][j];
}
}
}
return arr[m - 1][n - 1];
}
}
3. 不同路径-2
分析:这个题和1的区别在于 障碍的地方f[i][j] = 0,然后就是边界条件中在最上边和最左边不再是直接等于1了,而是由它前面一个来决定!
动态规划第一步:确定状态
a. 最后一步: 无论机器人最后是如何到达终点的,最后一步只有两种情况,那就是从左到右和从上到下。设目标位置为[m - 1][n -1],则是从[m-2][n-1]和[m - 1][n - 2]过来的。
b. 子问题,原问题是从[0][0]到[m-1][n-1]转化为有多少种方式从[0][0]走到[m-2][n-1]和有多少种方式从从[0][0]走到[m-1][n-2]
动态规划第二步:状态转移方程
f[i][j] = f[i - 1][j] + f[i][j - 1]
动态规划第三步:初始条件和边界条件
初始条件:f[0][0] = 1
边界条件:i = 0或者 j = 0, f[i][j] = f[i ][j - 1]或者f[i - 1][j]
动态规划第四步:计算顺序
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] arr = new int[m][n];
if(obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) {
return 0;
}else{
arr[0][0] = 1;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(obstacleGrid[i][j] == 1) {
arr[i][j] = 0;
}else{
if(i == 0 && j == 0){
arr[i][j] = 1;
}else{
if(i == 0) {
arr[i][j] = arr[i][j - 1];
}
if(j == 0) {
arr[i][j] = arr[i - 1][j];
}
if(i != 0 && j != 0) {
arr[i][j] = arr[i - 1][j]+ arr[i][j - 1];
}
}
}
}
}
}
return arr[m - 1][n - 1];
}
}
4. 跳跃游戏
分析:
动态规划第一步:确定状态
a. 最后一步: 无论怎么样到最后一步,都是前面的某一步直接跳过去的
b. 子问题,能成功跳到最后一步j位置是上一次跳成功了在i位置,并且i位置能跳的步数能够到j
动态规划第二步:状态转移方程
f[j] = or{i = 0到j-1}{f[i] && nums[i] > j - i}
动态规划第三步:初始条件和边界条件
初始条件:f[0]= true
边界条件:无
动态规划第四步:计算顺序
从小到大依次计算。
class Solution {
public boolean canJump(int[] nums) {
// f[j]是true的条件有两个
// 1. f[i] = true 2. nums[i] > j - i
if (nums == null || nums.length == 0) return false;
int n = nums.length;
boolean[] arr = new boolean[n+1];
arr[0] = true;
for(int i = 1; i < n; i++) {
arr[i] = false; // 这儿是个小细节
for(int j = 0; j < i; j++) {
if(arr[j] && nums[j] >= i - j) {
arr[i] = true;
break;
}
}
}
return arr[n - 1];
}
}
5. 粉刷房子
粉刷房子2请移步12题
题目
分析:
序列型动态规划:前i个最小/方式数/最小
序列➕状态
class Solution {
public int minCost(int[][] costs) {
int n = costs.length;// 房子的个数
int[][] arr = new int[3][n];
//arr[0][i] 代表第i栋房子是红色时,前i栋房子的最低价
// arr[1][i] 代表第i栋房子是蓝色时,前i栋房子的最低价
// arr[2][i] 代表第i栋房子是绿色时,前i栋房子的最低价
// 初始条件
for(int i = 0; i <