**动态规划 --小白学习之路
(强调:我就是个新手,我就是个弟弟,代码写的比较烂大佬们别骂我)
题目分类:
1.最值问题(理解为比较题)
2.数量问题(理解为加法题)
3.存在性问题(理解为判断题)
4.以上都是小弟自己瞎总结,大佬们别骂
解题思路:
将大问题分为一个个等价的子问题
题目(最值问题):
力扣剑指offer 42 .连续子数组的最大和
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
思路:最值问题可以理解为比较类型的问题,当我们需要找到当前数组的最大和,那么只有两种方法可以到达当前数组元素,
1.当前元素的前一个元素加上当前元素总和变得更大,则取当前数组和前一个数组的和。
2.反之,取当前元素为唯一元素 。
分割子问题为: fn[i] = Math.max(fn[i - 1] + nums[i], nums[i]);
那么只需要遍历一次即可得到最大的和
class Solution {
public int maxSubArray(int[] nums) {
int max = nums[0];
int [] fn = new int[nums.length];
fn[0] = nums[0];
for(int i = 1; i < nums.length; i++) {
fn[i] = 0;
fn[i] = Math.max(fn[i - 1] + nums[i], nums[i]);
max = Math.max(fn[i] , max);
}
return max;
}
}
力扣322零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
思路:和上一题一样,目前只有coins里面的钱币的金额才能到达amount,那么到达amount的方式只有
for(int i = 0; i < coins.length; i++) {
amount - coins[i] //这些
}
//换示例来说: 假如coins中有1,2,5面值的钱币,那么到达最终amount的前一步只能是amount - 1 , amount - 2 ,amount - 5这三种方式
那么分割为子问题式子为:
for(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]);
}
完整代码为:
class Solution {
public int coinChange(int[] coins, int amount) {
int[] f = new int [amount + 1] ;
int n = coins.length;
f[0] = 0;
int i , j;
for(i = 1; i <= amount; i++) {
f[i] = Integer.MAX_VALUE;
for(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]);
}
}
if(f[amount] == Integer.MAX_VALUE) return -1;
else return f[amount];
}
}
题目(数量问题)
力扣62不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
思路:我们到达最右下角,只有他的上面和他的左边才能到达,那么分割子问题为:想要知道到达当前的点的上面到达的方法和左边到达的方法即可
完整的代码为
class Solution {
public int uniquePaths(int m, int n) {
int[][] f = new int[m][n];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(i == 0 || j == 0) f[i][j] = 1;
else {
f[i][j] = f[i - 1][j] + f[i][j - 1]; //加减法问题
}
}
}
return f[m - 1][n - 1];
}
}
力扣 70 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
思路:假如向跳到当前的楼梯,那么你只有两种方法,你可以从比当前 台阶少一个的台阶跳上来,也可以从当前台阶少两个台阶的地方跳上来,是不是似曾相识的感觉哈哈哈哈
完整代码:
class Solution {
public int climbStairs(int n) {
int []fn = new int[n + 1];
fn[0] = 1;
fn[1] = 1;
for(int i = 2; i <= n; i++) {
fn[i] = fn[i - 1] + fn[i - 2];
}
return fn[n];
}
}
题目(存在性问题)
力扣55 跳跃游戏
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
思路:这题其实用动态规划太慢了,自己体会把嘿嘿
class Solution {
public boolean canJump(int[] nums) {
boolean [] f = new boolean[nums.length];
f[0] = true;
for(int i = 1; i < nums.length; i++) {
f[i] = false;
for(int j = 0; j < i; j++) {
if(f[j] == true && i - j<= nums[j]) {
f[i] = true;
break;
}
}
}
return f[nums.length - 1];
}
}