💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、豆包、星火、月之暗面及文生图、文生视频 广告
#### [120\. 三角形最小路径和](https://leetcode-cn.com/problems/triangle/) 使用 DFS(分治法) 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。 超时 ``` class Solution { public: int minimumTotal(vector<vector<int>>& triangle) { return helper(triangle, 0, 0); } int helper(vector<vector<int>>& triangle, int x, int y) { if (x == triangle.size() - 1) return triangle[x][y]; int down = helper(triangle, x + 1, y); int right = helper(triangle, x + 1, y + 1); return min(down, right) + triangle[x][y]; } }; ``` 记忆化搜索(本质:动态规划) ``` class Solution { public: int minimumTotal(vector<vector<int>>& triangle) { int len = triangle.size(); vector<vector<int>> mem(len, vector<int>(len, -1)); return helper(triangle, mem, 0, 0); } int helper(vector<vector<int>>& triangle, vector<vector<int>>& mem, int x, int y) { if (x == triangle.size() - 1) return triangle[x][y]; if (mem[x][y] != -1) return mem[x][y]; int down = helper(triangle, mem, x + 1, y); int right = helper(triangle, mem, x + 1, y + 1); mem[x][y] = min(down, right) + triangle[x][y]; return mem[x][y]; } }; ``` 动态规划就是把大问题变成小问题,并解决小问题重复计算的方法 动态规划和DFS的区别 * 二叉树子问题没有交集,所以大部分二叉树都是用递归或者分治法,即DFS,就可以解决 * 像triangle这种有重复走的情况,子问题有交集,所以可以用动态规划来解决 ``` // 自下往上-二维 class Solution { public: int minimumTotal(vector<vector<int>>& triangle) { int len = triangle.size(); if (len == 0) return 0; for (int i = len - 2; i >= 0; i--) for (int j = 0; j < triangle[i].size(); j++) { triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1]); } return triangle[0][0]; } }; ``` #### [64\. 最小路径和](https://leetcode-cn.com/problems/minimum-path-sum/) 给定一个包含非负整数的*m* x *n* 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 **说明:**每次只能向下或者向右移动一步。 超出时间限制 ``` class Solution { public: int minPathSum(vector<vector<int>>& grid) { vector<int> result; dfs(grid, 0, 0, 0, result); sort(result.begin(), result.end()); return result[0]; } void dfs(vector<vector<int>>& grid, int x, int y, int sum, vector<int>& result) { sum += grid[x][y]; int rowLen = grid.size(); int colLen = grid[0].size(); if (x == rowLen - 1 && y == colLen - 1) { result.push_back(sum); return; } if (x == rowLen - 1) dfs(grid, x, y + 1, sum, result); else if (y == colLen - 1) dfs(grid, x + 1, y, sum, result); else { dfs(grid, x + 1, y, sum, result); dfs(grid, x, y + 1, sum, result); } } }; ``` 动态规划 ``` class Solution { public: int minPathSum(vector<vector<int>>& grid) { if (grid.size() == 0) return 0; int rowLen = grid.size(); int colLen = grid[0].size(); for (int i = rowLen - 2; i >= 0; i--) { grid[i][colLen - 1] += grid[i + 1][colLen - 1]; } for (int i = colLen - 2; i >= 0; i--) { grid[rowLen - 1][i] += grid[rowLen - 1][i + 1]; } for (int i = rowLen - 2; i >= 0; i--) for (int j = colLen - 2; j >= 0; j--) { grid[i][j] += min(grid[i + 1][j], grid[i][j + 1]); } return grid[0][0]; } }; ``` #### [62\. 不同路径](https://leetcode-cn.com/problems/unique-paths/) 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 问总共有多少条不同的路径? 超出时间限制 ``` class Solution { public: int uniquePaths(int m, int n) { int result = 0; dfs(m, n, 1, 1, result); return result; } void dfs(int m, int n, int x, int y, int& result) { if (x == m && y == n) { result++; return; } if (x == m) dfs(m, n, x, y + 1, result); else if (y == n) dfs(m, n, x + 1, y, result); else { dfs(m, n, x, y + 1, result); dfs(m, n, x + 1, y, result); } } }; ``` 动态规划 ``` class Solution { public: int uniquePaths(int m, int n) { int result = 1; vector<vector<int>> dp(m, vector<int>(n, 1)); for (int x = m - 2; x >= 0; x--) for (int y = n - 2; y >= 0; y--) dp[x][y] = dp[x][y + 1] + dp[x + 1][y]; return dp[0][0]; } }; ``` #### [63\. 不同路径 II](https://leetcode-cn.com/problems/unique-paths-ii/) 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? 网格中的障碍物和空位置分别用 1 和 0 来表示。 说明:m 和 n 的值均不超过 100。 示例 1: 输入: [   [0,0,0],   [0,1,0],   [0,0,0] ] 输出: 2 解释: 3x3 网格的正中间有一个障碍物。 从左上角到右下角一共有 2 条不同的路径: 1. 向右 -> 向右 -> 向下 -> 向下 2. 向下 -> 向下 -> 向右 -> 向右 ``` class Solution { public: int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) { if (obstacleGrid.size() == 0) return 0; int m = obstacleGrid.size(); int n = obstacleGrid[0].size(); vector<vector<unsigned int>> dp(m, vector<unsigned int>(n, 0)); for (int x = m - 1; x >= 0; x--) { if (obstacleGrid[x][n - 1]) break; dp[x][n - 1] = 1; } for (int y = n - 1; y >= 0; y--) { if (obstacleGrid[m - 1][y]) break; dp[m - 1][y] = 1; } for (int x = m - 2; x >= 0; x--) for (int y = n - 2; y >= 0; y--) { if (obstacleGrid[x][y]) dp[x][y] = 0; else dp[x][y] = dp[x][y + 1] + dp[x + 1][y]; } return dp[0][0]; } }; ``` ## 序列类型(40%) #### [70\. 爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/) 假设你正在爬楼梯。需要*n* 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? **注意:**给定*n*是一个正整数。 ``` class Solution { public: int climbStairs(int n) { if (n <= 2) return n; int g = 1; int f = 2; for (int i = 3; i <= n; i++) { f = f + g; g = f - g; } return f; } }; ``` #### [55\. 跳跃游戏](https://leetcode-cn.com/problems/jump-game/) 给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 ``` class Solution { public: bool canJump(vector<int>& nums) { int most = 0; for (int i = 0; i < nums.size(); i++) { if (i > most) return false; most = max(most, nums[i] + i); } return true; } }; ``` #### [45\. 跳跃游戏 II](https://leetcode-cn.com/problems/jump-game-ii/) 给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 ``` class Solution { public: int jump(vector<int>& nums) { int n = nums.size(); int result = 0; int start = 0; int end = 0; while (end < n - 1) { int nextReach = end; for (int i = start; i <= end; i++) { nextReach = max(nextReach, nums[i] + i); } start = end + 1; end = nextReach; result++; } return result; } }; ``` #### [343\. 整数拆分](https://leetcode-cn.com/problems/integer-break/) ```cpp // 记忆化搜索 class Solution { private: vector<int> mem; int max3(int a, int b, int c) { return max(a, max(b, c)); } int breakInteger(int n) { if (n == 1) return 1; if (mem[n] != -1) return mem[n]; int res = -1; for (int i = 1; i <= n - 1; ++i) res = max3(res, i * (n - i), i * breakInteger(n-i)); mem[n] = res; return res; } public: int integerBreak(int n) { assert(n >= 2); mem = vector<int>(n+1, -1); return breakInteger(n); } }; // 动态规划 class Solution { private: int max3(int a, int b, int c) { return max(a, max(b, c)); } public: int integerBreak(int n) { assert(n >= 2); vector<int> mem(n+1, -1); mem[0] = 1; for (int i = 2; i <= n; ++i) { for (int j = 1; j <= i-1; ++j) mem[i] = max3(mem[i], j * (i - j), j * mem[i-j]); } return mem[n]; } }; ```