代码随想录day29:动态规划part2

ops/2024/10/10 23:04:55/

62. 不同路径 

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

也可以路径压缩,一维数组压缩到常量,二维数组压缩到一维

for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[j] += dp[j - 1]; // dp[j] = dp[j] (正上方) + dp[j - 1] (正左方)}
}外层循环遍历行 i,从第二行开始。
内层循环遍历列 j,从第二列开始。
对于每个位置 (i, j),更新 dp[j]:
dp[j] 代表到达当前列的路径数。
dp[j - 1] 是到达左边单元格的路径数。
通过 dp[j] += dp[j - 1],我们将上方的路径数(dp[j])和左方的路径数(dp[j - 1])相加,得到新的路径数。

63. 不同路径 II

class Solution {public int uniquePathsWithObstacles(int[][] obstacleGrid) {int m = obstacleGrid.length;int n = obstacleGrid[0].length;int[][] dp = new int[m][n];// 初始化第一列for (int i = 0; i < m; i++) {if (obstacleGrid[i][0] == 1) {dp[i][0] = 0;// 之后的所有行都应该是 0break; } else {dp[i][0] = 1;}}// 初始化第一行for (int j = 0; j < n; j++) {if (obstacleGrid[0][j] == 1) {dp[0][j] = 0;// 之后的所有列都应该是 0break; } else {dp[0][j] = 1;}}for(int i = 1; i < m; i++){for(int j = 1; j < n; j++){dp[i][j] = dp[i - 1][j] +dp[i][j - 1];if(obstacleGrid[i][j] == 1) dp[i][j] = 0;}}return dp[m - 1][n - 1];}
}

自己写的时候写错了第一行的初始化,

for(int i = 0; i < m; i++){if(obstacleGrid[i][0] == 1) {dp[i][0] = 0;} else {dp[i][0] = 1;}
}

没考虑到一个问题,如果第一列的某个单元格是障碍物(1),那么该行之后的所有单元格都应该是 0,因为无法通过障碍物。

所以需要在遇到障碍物后,停止设置后续单元格的值为 1。如最终代码那样写。

343. 整数拆分

class Solution {public int integerBreak(int n) {//dp[i] 为正整数 i 拆分后的结果的最大乘积int[] dp = new int[n+1];dp[2] = 1;for(int i = 3; i <= n; i++) {for(int j = 1; j <= i-j; j++) {// 这里的 j 其实最大值为 i-j,再大只不过是重复而已,//并且,在本题中,我们分析 dp[0], dp[1]都是无意义的,//j 最大到 i-j,就不会用到 dp[0]与dp[1]dp[i] = Math.max(dp[i], Math.max(j*(i-j), j*dp[i-j]));// j * (i - j) 是单纯的把整数 i 拆分为两个数 也就是 i,i-j ,再相乘//而j * dp[i - j]是将 i 拆分成两个以及两个以上的个数,再相乘。}}return dp[n];}
}

nmmd,很难

96. 不同的二叉搜索树

class Solution {Map<Integer, Integer> map = new HashMap<>();public int numTrees(int n) {if(n == 0 || n == 1) return 1;if(map.containsKey(n)) return map.get(n);int res = 0;for(int i = 1; i <= n; i++){int left = numTrees(i - 1);int right = numTrees(n - i);res += left * right;}map.put(n,res);return res;}
}

递归构造的性质

numTrees(n) 的实现中,节点的选择和拆分方式确保了生成的树都是 BST。以下是如何保证这一点的详细分析:

  1. 根节点的选择:

    • 在函数中,我们遍历所有可能的根节点 i,从 1n。选择 i 作为根节点意味着:
      • 所有小于 i 的节点(1i-1)将会在左子树中。
      • 所有大于 i 的节点(i+1n)将会在右子树中。
  2. 递归构造左子树和右子树:

    • 对于左子树,我们递归调用 numTrees(i - 1),计算左侧所有节点的组合。
    • 对于右子树,我们递归调用 numTrees(n - i),计算右侧所有节点的组合。
    • 这种递归方式保证了左子树和右子树的节点始终遵循 BST 的性质。
  3. 使用 Map 来存储已经计算过的结果,避免了重复计算。

这个题解是真牛逼,来自【阿秋】JAVA递归解法


http://www.ppmy.cn/ops/123690.html

相关文章

今日总结10.10

面向对象和面向过程的区别 面向过程编程&#xff08;Procedural-Oriented Programming&#xff0c;POP&#xff09;和面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;是两种常见的编程范式&#xff0c;两者的主要区别在于解决问题的方式不同…

Swift并发笔记

1.同步和异步 说到线程的执行方式&#xff0c;最基本的一组概念是同步和异步。所谓同步&#xff0c;就是在操作执行完成之前&#xff0c;运行操作的这个线程都会被占用&#xff0c;直到函数最终被抛出或返回。Swift5.5之前&#xff0c;func关键字声明的所有的函数都是同步的。…

Python+ffmpeg实现字幕视频合并

背景 我想给自己的视频添加字幕&#xff0c;但是市面上比较好的软件都不太对我口味&#xff0c;要么贵&#xff0c;要么就是学习版不给力。兜兜转转&#xff0c;我决定用多款开源软件分步实现&#xff0c;当然&#xff0c;也可以去白piao某些软件的字幕功能。 驱动力 ffmpeg…

米哈游Android面试题汇总及参考答案

Java 的内存回收机制是如何工作的? 在 Java 中,内存回收主要由垃圾回收器(Garbage Collector)来完成。 Java 的内存主要分为堆(Heap)和栈(Stack)等区域。其中,对象主要分配在堆上。当创建一个对象时,会在堆上为其分配内存空间。 垃圾回收器主要负责回收不再被使用的对…

146. LRU 缓存【 力扣(LeetCode) 】

零、原题链接 146. LRU 缓存 一、题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff…

穷人就不该乱买电车

文 | AUTO芯球 作者 | 雷慢 买车最怕的是什么你知道吗&#xff1f; 是没钱的穷人还要去买豪华电车&#xff0c; 比买电车更可怕的是什么你知道吗&#xff1f; 是买了电车没两年又卖了&#xff01; 真不是讲鬼故事&#xff0c; 新能源车尤其是纯电车&#xff0c;一年打五折…

掌握 C# 中的 LINQ(语言集成查询)

LINQ&#xff08;Language Integrated Query&#xff0c;语言集成查询&#xff09;是 C# 中的一项强大功能&#xff0c;它使得我们能够使用查询语法处理不同的数据源&#xff0c;如对象、XML、数据库等。LINQ 通过提供统一的查询语法&#xff0c;使开发者能够更加简洁、高效地操…

设计模式之---工厂模式

设计模式–工厂模式 一 什么是工厂模式 使用工厂模式是为了将创建对象的具体过程屏蔽隔离起来 快速的将对象实例化 从而提高了代码的灵活性和改善了简洁性&#xff0c;工厂模式具体分为以下三类&#xff1a; 1 简单工厂模式&#xff08;Simple Factory&#xff09; 2 工厂方…