动态规划
题目
1143. 最长公共子序列 - 力扣(LeetCode)
公共子序列,类似于最长重复子数组,但是不要求连续 (子序列)
1. 定义 dp,dp[i][j]
表示以 i-1 与 j-1 结尾的最长公共子序列的长度
2. 定义递推公式
如果字符相同,则在基础上+1
if (text1[i-1] == text2[i-1]) dp[i][j] = dp[i-1][j-1] +1
如果字符不同,分别屏蔽 i-1 和 j-1 对比字符
else dp[i][j] = std::max(dp[i][j-1], dp[i-1][j])
3. 初始化 dp,由于 dp 是从前往后推导,且定义为 i-1, j-1
其中 0-1 时候结果为 0 意思是字符串与空字符查找那最大的公共子序列结果为 0
4. 遍历顺序是从前往后,从上到下遍历
5. 打印 dp
int longestCommonSubsequence(string text1, string text2) {// 定义dp数组std::vector<std::vector<int>> dp(text1.size()+1, std::vector<int>(text2.size()+1, 0));// 遍历dp数组for (int i = 1; i <= text1.size(); ++i) {for (int j = 1; j <= text2.size(); ++j) {// 递推公式两种情况if (text1[i-1] == text2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;else dp[i][j] = std::max(dp[i-1][j], dp[i][j-1]);}}return dp[text1.size()][text2.size()];
}
1035. 不相交的线 - 力扣(LeetCode)
本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!
1. 定义 dp,dp[i][j]
表示以 i-1 j-1
结尾的最长公共子序列长度
2. 递推公式类上题
3. 初始化类似上题
4. 遍历顺序同上题
5. 打印 dp
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {// 定义dp数组 i-1 j-1 结尾之前最大的公共子序列std::vector<std::vector<int>> dp(nums1.size()+1, std::vector<int>(nums2.size()+1, 0));// forfor (int i = 1; i <= nums1.size(); ++i) {for (int j = 1; j <= nums2.size(); ++j) {if (nums1[i-1] == nums2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;else dp[i][j] = std::max(dp[i-1][j], dp[i][j-1]);}}return dp[nums1.size()][nums2.size()];
}
53. 最大子数组和 - 力扣(LeetCode)
之前贪心做过 [[Day27 贪心Ⅰ 分饼干 摆动序列 最大子序列和#题目]],贪心就是小于 0不取
使用 dp 再做一遍,整体类似于基本的 dp 如打家劫舍、股票
1. 定义 dp,dp[i]
表示 i 之前的最大连续子数组和
2. 递推公式:基于之前的结果与当前结果的最大值作为当前 i 的 dp 值
dp[i] = max(dp[i-1]+nums[i], nums[i])
3. 初始化由于都是从前面推导的,因此 dp[0] = nums[0]
最大和要寻找 dp 最大值,使用 res 比较获取
4. 遍历顺序从前往后
5. 打印 dp
int maxSubArray(vector<int>& nums) {// 定义dp数组std::vector<int> dp(nums.size(), 0);// 初始化dp res也定义为nums[0]值保不忽略第一个元素dp[0] = nums[0];int res = nums[0];// 遍历dpfor (int i = 1; i < nums.size(); ++i) {dp[i] = std::max(dp[i-1] + nums[i], nums[i]);if (dp[i] > res) res = dp[i];}return res;
}
392. 判断子序列 - 力扣(LeetCode)
编辑距离问题,本体的本质就是求 s 与 t 的最长公共子序列,只不过这个 s 不可删除
1. dp[i][j]
表示 i-1, j-1
为结尾的 s/t 字符串的最长公共子序列的长度
2. 递推公式类似求最长公共子序列固定 s 不变,只删除 t(dp[i][j-1]
)
if(s[i-1] == t[j-1]) dp[i][j] = dp[i-1][j-1]+1
else dp[i][j] = dp[i][j-1]
3. 初始化 dp 数组
因为定义为 i-1,j-1
因此初始化为 0 即可,之后使用递推公式就可以推出
4. 遍历顺序从前往后遍历,结果与 s 相等说明可以匹配
5. 打印 dp
bool isSubsequence(string s, string t) {// 定义dpstd::vector<std::vector<int>> dp(s.size()+1, std::vector<int>(t.size()+1, 0));// 遍历dpfor (int i = 1; i <= s.size(); ++i) {for (int j = 1; j <= t.size(); ++j) {// 递推公式if (s[i-1] == t[j-1]) dp[i][j] = dp[i-1][j-1] + 1;else dp[i][j] = dp[i][j-1]; // t 删除 匹配s}}if (dp[s.size()][t.size()] == s.size()) return true;else return false;
}