文章目录
- 1、动态规划
- 2、leetcode509:斐波那契数列
- 3、leetcode62:不同路径
- 4、leetcode121:买卖股票的最佳时机
- 5、leetcode70:爬楼梯
- 6、leetcode279:完全平方数
- 7、leetcode221:最大正方形
1、动态规划
只能向下、向右的走,从图中左上角走到右下角,有几条路径
因为只能向下、向右走,所以从起始点走到点(R,C),路径数等于,以起始点到点(R,C)为对角线的矩形里,到点(R,C)左侧点的路径数 + 到点(R,C)上边点的路径数 (动态规划的方程式)
// 动态规划的方程式
[R,C] = [R - 1][C] + [R][C - 1]
有些类似斐波那契数列了,起始点就是[0][0] (动态规划的初始状态),那递归终止的条件,就是其左侧点或者上边点不存在,此时,到它的路径只有一条,return 1,一直算到点(R,C)(动态规划的终止状态)。以上,动态规划的三要素:
- 动态规划的方程式
- 动态规划的初始状态
- 动态规划的终止状态
从起始状态(0,0),到终止状态(R,C),中间每个格子的值(到达它的路径数),都会算出来,这些中间结果,可存入一个数组,这题可用二维数组存。动态规划可用来干:
- 1)计数:有多少种方式或路径,如上面从左上角到右下角有多少路径
- 2)求最值:从左上角到右下角路径的最大数字和,每个数字不等,代表权重,求最长路径或最小路径
- 3)求存在性:是否存在某个可能,可以从A走到B
动态规划的分类:
-
自底向上:从最小的子问题开始,逐步计算出所有可能的状态,直到解决原问题
-
自顶向下:通过递归地方式,从原问题开始,依次分解为更小的子问题,通常需要记忆化搜索(Memoization)来保存已经计算过的结果,避免重复计算
2、leetcode509:斐波那契数列
不再递归了,根据方程式,步步为营,从F(2)一路计算到F(n),并把每个中间值存入数组中,最后返回数组的第n个元素即可
public class P509Two {
public int recursion(int n) {
//F(0)和F(1)
if (n < 2) {
return n == 0 ? 0 : 1;
}
int[] dp = new int[n + 1];
dp[1] = 1; //F(1)
// 根据方程式,计算每个值,存入数组,从F(2)一路计算到F(5)
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
3、leetcode62:不同路径
前面已经分析过了,这儿的方程式为:F(m,n)= F(m - 1,n)+ F(m,n - 1),初始状态为(1,1),终止状态为(m,n)
public class P62 {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
dp[0][0] = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 如果是边缘,x轴或者y轴,则直接赋值1,因为只有一条路可达,其余按方程式赋值
if (i == 0 || j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
红圈里的这些,x轴或者y轴上的,到达他们的路径只有一条,因此直接赋值1,别用方程式去计算,会导致数组下标越界。除了这些点,其余按方程式赋值,最后返回(m-1,n-1)位置的值即可。
两道题,给我的个人感觉是,动态规划,就是从初始状态开始,根据方程式,步步为营,经过一个个中间状态的值,到达终止状态 ,最后,如果你需要存储这些中间状态值,一般用数组存储,因为其访问数据的时间复杂度为O(1)。
4、leetcode121:买卖股票的最佳时机
这题,本质就是求数组后面元素与前面元素的差值的最大值,两层for循环,默认返回为0,遇到最大的值就覆盖,即可:
优化下:遍历数组,更新前 i 天的最低买入成本,同时更新前i天的最高利润(第i天与前面i-1天最低价的差值,然后不停覆盖这个差值,取最大值)
5、leetcode70:爬楼梯
参考上面62题不同路径的思想:
- 62题:到(m,n)的路径数 = 到(m,n)上方点的路径数 + 到(m,n)左侧点的路径数,因为规定了只能向下、向右移动
- 本题:到n阶的路径数 = 到n - 1阶的路径数 + 到 n - 2阶的路径数,因为一次只能走一个或者两个台阶
切入点:动态规划要经过状态转移,那就该想一下,题中要求的状态,怎么可以由上一步到达
由此,动态规划方程式为:
f(n) = f(n - 1) + f(n - 2)
代码实现:
6、leetcode279:完全平方数
思路一:暴力解法
根据四平方和定理,这题返回的结果肯定是1、2、3、4里的一个。那我找:n是否能由1个平方数搞出来,不行就看是否能由2个平方数搞出来,最多到4,封顶了就。因为这题求的是最少的数量,别说n = 1 + 1 + 1 + …… + 1。借助以下四条数学规律:
实现: