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

[Algorithm][动态规划][两个数组的DP][正则表达式匹配][交错字符串][两个字符串的最小ASCII删除和][最长重复子数组]详细讲解

目录

  • 1.正则表达式匹配
    • 1.题目链接
    • 2.算法原理详解
    • 3.代码实现
  • 2.交错字符串
    • 1.题目链接
    • 2.算法原理详解
    • 3.代码实现
  • 3.两个字符串的最小ASCII删除和
    • 1.题目链接
    • 2.算法原理详解
    • 3.代码实现
  • 4.最长重复子数组
    • 1.题目链接
    • 2.算法原理详解
    • 3.代码实现


1.正则表达式匹配

1.题目链接

  • 正则表达式匹配

2.算法原理详解

  • 思路
    • 确定状态表示 -> dp[i][j]的含义

      • dp[i]j]p[0, j]区间内的子串能否匹配s[0, i]区间内的子串
    • 推导状态转移方程:根据最后一个位置的情况,分情况讨论

      • 结论
        请添加图片描述

      • 推导过程
        请添加图片描述

      • 本题若直接按照如下的状态转移方程去写,时间复杂度会到 O ( N 3 ) O(N^3) O(N3)

      • 所以需要想办法优化

    • 优化

      • 方法一:数学推导
        请添加图片描述

      • 方法二:根据状态表示以及实际情况,优化状态转移方程 -> 抽象,难理解:(

        • 实际相当于保留了*,把状态传递给前面
          请添加图片描述
    • 初始化:

      • 多开一行及一列虚拟结点
        请添加图片描述
    • 确定填表顺序:从上往下,从左往右

    • 确定返回值:dp[n][m]


3.代码实现

bool isMatch(string s, string p) 
{int n = s.size(), m = p.size();s = " " + s, p = " " + p;vector<vector<bool>> dp(n + 1, vector<bool>(m + 1));// Initdp[0][0] = true;for(int i = 2; i <= m; i += 2){if(p[i] == '*'){dp[0][i] = true;}else{break;}}// DPfor(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){if(p[j] == '*'){dp[i][j] = dp[i][j - 2] || (p[j - 1] == '.' || p[j - 1] == s[i]) && dp[i - 1][j];}else{dp[i][j] = (p[j] == s[i] || p[j] == '.') && dp[i - 1][j - 1];}}}return dp[n][m];
}

2.交错字符串

1.题目链接

  • 交错字符串

2.算法原理详解

  • 预处理s1 = " " + s1, s2 = " " + s2, s3 = " " + s3

    • 目的:此时可以很简便的用s1s2的下标就计算到s3的的下标
      请添加图片描述
  • 思路

    • 确定状态表示 -> dp[i][j]的含义

      • dp[i]j]s1[1, i]区间内的字符串以及s2[1, j]区间内的字符串,能否拼接凑成s3[1, i + j]区间内的字符串
    • 推导状态转移方程:根据最后一个位置的情况,分情况讨论
      请添加图片描述

    • 初始化:

      • 多开一行及一列虚拟结点
        请添加图片描述
    • 确定填表顺序:从上往下,从左往右

    • 确定返回值:dp[n][m]


3.代码实现

bool isInterleave(string s1, string s2, string s3) 
{int n = s1.size(), m = s2.size();if(n + m != s3.size()) return false;s1 = " " + s1, s2 = " " + s2, s3 = " " + s3;vector<vector<bool>> dp(n + 1, vector<bool>(m + 1));// Initdp[0][0] = true;for(int i = 1; i <= m; i++) // 第一行{if(s2[i] == s3[i]){dp[0][i] = true;}else{break;}}for(int i = 1; i <= n; i++) // 第一列{if(s1[i] == s3[i]){dp[i][0] = true;}else{break;}}// DPfor(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){dp[i][j] = (s1[i] == s3[i + j] && dp[i - 1][j])|| (s2[j] == s3[i + j] && dp[i][j - 1]);}}return dp[n][m];
}

3.两个字符串的最小ASCII删除和

1.题目链接

  • 两个字符串的最小ASCII删除和

2.算法原理详解

  • 问题转化:删除后,公共子序列中,ASCII和最大的 —> 正难则反
  • 思路
    • 确定状态表示 -> dp[i][j]的含义

      • dp[i]j]s1[0, i]区间以及s2[0, j]区间内的所有的子序列里,公共子序列ASCII最大和
    • 推导状态转移方程:根据最后一个位置的情况,分情况讨论
      请添加图片描述

    • 初始化:vector<vector<int>> dp(n + 1, vector<int>(m + 1))

    • 确定填表顺序:从上往下,从左往右

    • 确定返回值:

      • 统计2个字符串的ASCII和sum
      • sum - dp[n][m] * 2

3.代码实现

int minimumDeleteSum(string s1, string s2) 
{int n = s1.size(), m = s2.size();vector<vector<int>> dp(n + 1, vector<int>(m + 1));for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);if(s1[i - 1] == s2[j - 1]){dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + s1[i - 1]);}}}int ret = 0;for(auto& ch : s1){ret += ch;}for(auto& ch : s2){ret += ch;}return ret - dp[n][m] * 2;
}

4.最长重复子数组

1.题目链接

  • 最长重复子数组

2.算法原理详解

  • 思路
    • 确定状态表示 -> dp[i][j]的含义

      • dp[i]:选取[0, i]一段区间内的所有子数组 ×
        • 因为此时无法知道最长子数组在哪儿,可能在中间,此时无法正确表示状态
      • dp[i][j]nums1[i]中以i位置元素为结尾的所有的子数组以及nums2中以j位置元素为结尾的所有的子数组中,最长重复子数组的长度
    • 推导状态转移方程:根据最后一个位置的情况,分情况讨论
      请添加图片描述

    • 初始化:vector<vector<int>> dp(n + 1, vector<int>(m + 1))

    • 确定填表顺序:从上往下

    • 确定返回值:dp表里面的最大值


3.代码实现

int findLength(vector<int>& nums1, vector<int>& nums2) 
{int n = nums1.size(), m = nums2.size();vector<vector<int>> dp(n + 1, vector<int>(m + 1));int ret = 0;for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){if(nums1[i - 1] == nums2[j - 1]){dp[i][j] = dp[i - 1][j - 1] + 1;ret = max(ret, dp[i][j]);}}}return ret;
}

相关文章:

  • 游戏研发(策略+sass+回调模式)
  • spring入门
  • 【二进制部署k8s-1.29.4】十一、metallb的安装部署
  • 【FPGA】Verilog语言从零到精通
  • Unity世界坐标下UI始终朝向摄像机
  • LangChain学习之prompt格式化与解析器使用
  • FreeReg运行笔记
  • vim常用使用技巧
  • 多目标应用:NSGA2求解无人机三维路径规划(MATLAB代码)
  • 【C++题解】1074 - 小青蛙回来了
  • CLion配置
  • 在今日头条上写文章:ChatGPT完整使用教程
  • 【qt】项目移植
  • elk:使用filebeat采集日志发送到kafka
  • Java装饰器模式,装饰器模式通常通过创建一个接口和一个或多个实现了该接口的类来开始,然后创建装饰器类,这些类也实现了相同的接口
  • 03Go 类型总结
  • Angular 响应式表单之下拉框
  • docker python 配置
  • Druid 在有赞的实践
  • Git初体验
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • JDK9: 集成 Jshell 和 Maven 项目.
  • Leetcode 27 Remove Element
  • MyEclipse 8.0 GA 搭建 Struts2 + Spring2 + Hibernate3 (测试)
  • mysql_config not found
  • php的插入排序,通过双层for循环
  • php中curl和soap方式请求服务超时问题
  • Redash本地开发环境搭建
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • Vue实战(四)登录/注册页的实现
  • 从0实现一个tiny react(三)生命周期
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 两列自适应布局方案整理
  • 前端相关框架总和
  • 小程序01:wepy框架整合iview webapp UI
  • 译自由幺半群
  • 原生Ajax
  • Hibernate主键生成策略及选择
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • #经典论文 异质山坡的物理模型 2 有效导水率
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .net core 控制台应用程序读取配置文件app.config
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .net6+aspose.words导出word并转pdf
  • .net和jar包windows服务部署
  • .Net实现SCrypt Hash加密
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • /etc/shadow字段详解
  • [28期] lamp兄弟连28期学员手册,请大家务必看一下
  • [acm算法学习] 后缀数组SA