当前位置: 首页 > news >正文

动态规划专练:力扣第718、1143题

力扣第718题-最长重复子数组

1.本题是一道考察动态规划的经典问题,设置一个二维dp[nums1Size + 1][nums2Size + 1]数组,来记录长度为i的nums1和长度为j的nums2的最长公共子数组长度,元素初始化为0。当nums1[i - 1] == nums2[j - 1]时说明当前元素相同,此时的最长公共子数组长度dp[i][j]就等于dp[i - 1][j - 1] + 1。每次循环都更新当前最长的公共子数组长度res。完整代码如下:

1. int findLength(int* nums1, int nums1Size, int* nums2, int nums2Size) { 2. // dp[i][j]:nums1前i个、nums2前j个元素,以nums1[i-1]、nums2[j-1]结尾的最长公共子数组长度 3. int dp[nums1Size + 1][nums2Size + 1]; 4. // 初始化dp数组全部置0 5. for (int i = 0; i <= nums1Size; i++){ 6. memset(dp[i], 0, sizeof(dp[i])); 7. } 8. 9. int res = 0; 10. // 遍历nums1每一位 11. for (int i = 1; i <= nums1Size; i++){ 12. // 遍历nums2每一位 13. for (int j = 1; j <= nums2Size; j++){ 14. // 当前两数字相等,公共子数组长度 = 左上角dp值 + 1 15. if (nums1[i - 1] == nums2[j - 1]){ 16. dp[i][j] = dp[i - 1][j - 1] + 1; 17. } 18. // 不相等时dp[i][j]保持0,更新全局最大长度 19. res = fmax(res, dp[i][j]); 20. } 21. } 22. 23. return res; 24. }

该算法时间复杂度和空间复杂度均为O(nums1Size * nums2Size)。

2.可以看到递推公式中当前项的dp只和上一层的有关,所以可以将二维dp数组改为一维动态dp数组。需要注意的是此时的内层循环就需要逆序遍历,防止元素被重复计算,同时当nums1[i - 1] != nums2[j - 1]时说明连续子数组在这里断掉了,需要将当前dp值置零。完整代码如下:

1. int findLength(int* nums1, int nums1Size, int* nums2, int nums2Size) { 2. // 一维滚动dp数组,dp[j]表示nums1前i个、nums2前j个以末尾元素结尾的最长公共子数组长度 3. int dp[nums2Size + 1]; 4. // 数组初始化为0 5. memset(dp, 0, sizeof(dp)); 6. 7. int res = 0; 8. // 遍历nums1每一个元素 9. for (int i = 1; i <= nums1Size; i++){ 10. // 倒序遍历nums2,防止dp[j-1]提前被覆盖 11. for (int j = nums2Size; j >= 1; j--){ 12. if (nums1[i - 1] == nums2[j - 1]){ 13. // 当前元素匹配,继承左上方dp[j-1]的值并+1 14. dp[j] = dp[j - 1] + 1; 15. } else { 16. // 元素不匹配,以当前位置结尾的公共子数组长度归零 17. dp[j] = 0; 18. } 19. // 更新全局最长公共子数组长度 20. res = fmax(res, dp[j]); 21. } 22. } 23. 24. return res; 25. }

该算法时间复杂度为O(nums1Size * nums2Size),空间复杂度为O(nums2Size)。

力扣第1143题-最长公共子序列

1.本题和力扣第718题-最长重复子数组比较相似,区别在于本题的公共子序列不要求连续,这就代表最长公共子序列的值在dp数组中可以继承而不是清零。当text1[i - 1] == text2[j - 1]时递推公式仍为dp[i][j] = dp[i - 1][j - 1] + 1,而不相等时就要比较上方或者左边的较大值来继承(从这两个方向前进一步都可以到达当前位置,所以有两种情况),递推公式为dp[i][j] = fmax(dp[i - 1][j], dp[i][j - 1])。完整代码如下:

1. int longestCommonSubsequence(char* text1, char* text2) { 2. // 获取两个字符串长度 3. int len1 = strlen(text1); 4. int len2 = strlen(text2); 5. // dp[i][j]:text1前i个字符、text2前j个字符的最长公共子序列长度 6. int dp[len1 + 1][len2 + 1]; 7. // 将dp数组全部初始化为0 8. for (int i = 0; i <= len1; i++){ 9. memset(dp[i], 0, sizeof(dp[i])); 10. } 11. 12. // 遍历text1每个字符 13. for (int i = 1; i <= len1; i++){ 14. // 遍历text2每个字符 15. for (int j = 1; j <= len2; j++){ 16. if (text1[i - 1] == text2[j - 1]){ 17. // 字符相等,公共子序列长度等于左上角值+1 18. dp[i][j] = dp[i - 1][j - 1] + 1; 19. } else { 20. // 字符不等,取上方或左方较大值 21. dp[i][j] = fmax(dp[i - 1][j], dp[i][j - 1]); 22. } 23. } 24. } 25. 26. // 两字符串全部字符对应的最长公共子序列结果 27. return dp[len1][len2]; 28. }

该算法时间复杂度和空间复杂度均为O(len1 * len2)。

2.本题也可以使用一维动态dp数组,内层循环由于在字符不等的情况下必须比较同行左边的和上一次当前位置的值,所以dp[j - 1]需要使用已经更新后的值,必须使用正序遍历。同时为了避免元素被重复使用,需要一个记录之前元素的变量pre和一个记录当前元素的变量cur来辅助(之前都是通过逆序来解决)。完整代码如下:

1. int longestCommonSubsequence(char* text1, char* text2) { 2. int len1 = strlen(text1); 3. int len2 = strlen(text2); 4. // 一维滚动dp数组,dp[j]代表text1前i个字符、text2前j个字符的LCS长度 5. int dp[len2 + 1]; 6. memset(dp, 0, sizeof(dp)); 7. 8. for (int i = 1; i <= len1; i++){ 9. // pre保存dp[j-1]更新前的值,等价二维dp[i-1][j-1] 10. int pre = dp[0]; 11. for (int j = 1; j <= len2; j++){ 12. // 记录更新前的dp[j],作为下一轮j+1的pre 13. int cur = dp[j]; 14. if (text1[i - 1] == text2[j - 1]){ 15. // 字符匹配,取左上角pre+1 16. dp[j] = pre + 1; 17. } else { 18. // 不匹配,取上方旧dp[j]或左侧新dp[j-1]最大值 19. dp[j] = fmax(dp[j], dp[j - 1]); 20. } 21. pre = cur; 22. } 23. } 24. 25. return dp[len2]; 26. }

该算法时间复杂度为O(len1 * len2),空间复杂度为O(len2)。

3.遍历方向由状态转移方程中最严苛的依赖限制唯一决定。只要推导分支中存在任何对当前行(新数据,如dp[i][j-1])的依赖,就强制要求正序遍历。在此强制正序的前提下,为解决同时需要上一行旧数据(如dp[i-1][j-1])造成的读写冲突,不改变遍历方向,而是通过引入标量缓存(即pre变量)进行空间置换。

http://www.jsqmd.com/news/1392715/

相关文章:

  • OpenCV C++复刻PS曲线调色实战|全网独家复现样条插值LUT查表、强化图像光影层次、助力摄影修图、工业影像校正、视觉预处理高效优化​
  • 哪款远控最适合个人长期使用?5款工具盘点,向日葵不限时长次数
  • 第28章 案例实战:逆光人像HDR
  • 开题直接一遍过✅Paperxie智能开题报告|告别导师反复打回
  • 新手避坑指南:MCP开发中最常见的10个错误
  • 2026年国内GEO数据监测工具盘点:从监测指标到适用场景解析 - 甄选测评馆
  • Java转AI实录:从0到1搭个LangChain Agent,我踩了这5个坑
  • 领创中等专业学校招生咨询电话开通,选专业报名咋办电话里问清 - 官方资讯
  • 同城中台系统核心表设计与模块启用状态机(代码深讲)
  • 通知,武汉三个区已经发通知领取评审表+资料袋
  • 别再一页页截图了,这款开源工具让你免费下载 Book118 文档
  • AI可以预测面试问题吗-AI反向押题法基于简历JD面经数据预测面试官会问什么
  • 沈阳皇姑区楼顶漏水怎么解决?2026 专业防水公司分享卫生间、楼顶、外墙、阳台 + 阳光房渗漏专业解决方案,一站式解决房屋漏水难题 - 超人防水
  • 动态规划专练:力扣第1035、392题
  • Tools原语深度解析:从定义到调用全流程
  • UPC码怎么用?亚马逊上架与编码管理完整指南
  • XML Schema 字符串数据类型详解
  • 2026年GIS三维软件公司推荐:这几家口碑好且专业 - 选型|行业|价格|案例
  • 别再翻页截图了:GetQzonehistory让QQ空间历史说说备份一次搞定
  • 合肥蜀山区楼顶漏水怎么解决?2026 专业防水公司分享卫生间、楼顶、外墙、阳台 + 阳光房渗漏专业解决方案,一站式解决房屋漏水难题 - 超人防水
  • fSpy-Blender 终极拆解:一张照片如何在几分钟内重建出透视精准的 3D 场景
  • 2026年拍卖平台行业发展白皮书 和拍网运营体系详解 - 起跑123
  • 眉山电脑回收哪家靠谱?先看这几点资质口碑判断心里有底 - 官方资讯
  • Agent 评测的数据飞轮:如何把 Good Case 和 Bad Case 变成回归资产
  • 被会员墙、广告弹窗、强制登录折磨了三年,这款开源下载工具让我彻底卸载了某雷
  • 2026年工业水处理药剂价格选型分析:代表性品牌推荐与趋势指南 - 全域品牌推荐
  • 2026 河北拍摄剪辑教学实体店短视频制作学习攻略 - 中国华商产业观察网
  • 深度 | Rubin Ultra 双芯重构:CoWoS-L 翘曲如何逼 NVIDIA 放弃 1TB 旗舰
  • 2026年,口碑好的成都整厂设备回收服务商揭秘! - 甄选测评馆
  • 对标 Claude Cowork:DeepSeek Harness 公测,同步开放插件生态