递归填写dp表
利用递归函数填写dp表,可以很容易完成边界的处理,并且不用考虑填表的顺序.
绝大部分的动态规划可以用递归填表.
不用考虑填表顺序,只需要遍历一遍dfs即可.
64. 最小路径和
给定一个包含非负整数的
m
x
n
网格grid
,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。
示例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]] 输出:7 解释:因为路径 1→3→1→1→1 的总和最小。
示例 2:
输入:grid = [[1,2,3],[4,5,6]] 输出:12
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 200
0 <= grid[i][j] <= 200
class Solution {
public:using ll = long long;vector<vector<int>> grid; // 定义二维网格gridint n, m; // 网格的行数和列数vector<vector<int>> dp; // 动态规划表void solveinit() {n = grid.size(); // 获取网格行数m = grid[0].size(); // 获取网格列数dp.clear(); // 清空动态规划表dp.resize(n, vector<int>(m, -1)); // 初始化动态规划表为-1dp[0][0] = grid[0][0]; // 设置初始值}int dfs(int i, int j) {if (i < 0 || j < 0)return INT_MAX; // 若坐标越界返回INT_MAXif (dp[i][j] != -1)return dp[i][j]; // 若已计算过直接返回结果dp[i][j] = grid[i][j] + min(dfs(i - 1, j), dfs(i, j - 1)); // 动态规划方程return dp[i][j];}int minPathSum(vector<vector<int>>& _grid) {grid = _grid; // 将输入网格赋值给成员变量gridsolveinit(); // 初始化for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (i == 0 && j == 0)continue;dfs(i, j); // 计算每个位置的最小路径和}}return dp[n - 1][m - 1]; // 返回右下角的最小路径和}
};
79. 单词搜索
给定一个
m x n
二维字符网格board
和一个字符串单词word
。如果word
存在于网格中,返回true
;否则,返回false
。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例 1:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" 输出:true
示例 2:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE" 输出:true
示例 3:
输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB" 输出:false
提示:
m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board
和word
仅由大小写英文字母组成进阶:你可以使用搜索剪枝的技术来优化解决方案,使其在
board
更大的情况下可以更快解决问题?
1.
正常的dfs搜索题目.
class Solution {
public:using ll = long long;vector<vector<char>> board; // 定义二维字符网格boardstring word; // 目标单词int n, m; // 网格的行数和列数vector<vector<bool>> visited; // 记录访问状态const int dx[4] = {1, -1, 0, 0}; // 右、左、下、上的方向数组const int dy[4] = {0, 0, 1, -1}; // 右、左、下、上的方向数组int index; // 当前匹配到的单词字符索引void solveinit() {n = board.size(); // 获取行数m = board[0].size(); // 获取列数visited.clear(); // 清空访问状态visited.resize(n, vector<bool>(m)); // 初始化访问状态index = 0; // 初始化单词字符索引}bool dfs(int i, int j) {visited[i][j] = true; // 标记当前位置已访问index++; // 单词索引递增if (index == word.size()) {return true; // 单词匹配完成,返回true}for (int k = 0; k < 4; k++) {int x = i + dx[k];int y = j + dy[k];if (x >= 0 && x < n && y >= 0 && y < m && !visited[x][y] &&board[x][y] == word[index]) {if (dfs(x, y))return true; // 深度优先搜索相邻位置}}index--; // 恢复单词字符索引visited[i][j] = false; // 回溯访问状态return false;}bool exist(vector<vector<char>>& _board, string _word) {board = _board; // 将输入网格赋值给成员变量boardword = _word; // 将输入单词赋值给成员变量wordsolveinit(); // 初始化for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (board[i][j] == word[index]) {if (dfs(i, j))return true; // 对每个起点进行深度优先搜索}}}return false; // 未找到匹配的路径,返回false}
};
1143. 最长公共子序列
给定两个字符串
text1
和text2
,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回0
。一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,
"ace"
是"abcde"
的子序列,但"aec"
不是"abcde"
的子序列。两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
示例 1:
输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace" ,它的长度为 3 。
示例 2:
输入:text1 = "abc", text2 = "abc" 输出:3 解释:最长公共子序列是 "abc" ,它的长度为 3 。
示例 3:
输入:text1 = "abc", text2 = "def" 输出:0 解释:两个字符串没有公共子序列,返回 0 。
提示:
1 <= text1.length, text2.length <= 1000
text1
和text2
仅由小写英文字符组成。
class Solution {
public:string text1, text2; // 定义两个字符串text1和text2int n, m; // 字符串text1和text2的长度vector<vector<int>> dp; // 动态规划表void solveinit() {n = text1.size(), m = text2.size(); // 获取字符串长度dp.clear(), dp.resize(n, vector<int>(m, -1)); // 初始化动态规划表为-1}int dfs(int i, int j) {if (i < 0 || j < 0)return 0; // 越界情况返回0if (dp[i][j] != -1)return dp[i][j]; // 若已计算过直接返回结果if (text1[i] == text2[j]) {dp[i][j] = dfs(i - 1, j - 1) + 1; // 字符相等时更新动态规划表} else {dp[i][j] = max(dfs(i - 1, j), dfs(i, j - 1)); // 字符不等时取左上方和上方的最大值}return dp[i][j];}int longestCommonSubsequence(string _text1, string _text2) {text1 = _text1; // 初始化字符串text1text2 = _text2; // 初始化字符串text2solveinit(); // 初始化for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {dfs(i, j); // 计算最长公共子序列长度}}return dp[n - 1][m - 1]; // 返回最终结果}
};
结尾
最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!