【算法攻坚】实现简易正则匹配

简介: 【算法攻坚】实现简易正则匹配

今日题目


给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。

'.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。


示例 1:


输入:s = "aa" p = "a" 输出:false 解释:"a" 无法匹配 "aa" 整个字符串。


示例 2:


输入:s = "aa" p = "a*" 输出:true 解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。


示例 3:


输入:s = "ab" p = "." 输出:true 解释:"." 表示可匹配零个或多个('*')任意字符('.')。


示例 4:


输入:s = "aab" p = "c*a*b" 输出:true 解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。


示例 5:


输入:s = "mississippi" p = "mis*is*p*." 输出:false


提示:

1 <= s.length <= 20 1 <= p.length <= 30 s 可能为空,且只包含从 a-z 的小写字母。 p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 保证每次出现字符 * 时,前面都匹配到有效的字符


思路


如果在实际开发过程中遇到类似的需求可千万别想着自己实现正则匹配

重复造轮子是对前辈的最大不尊敬,各个编程语言都有着现成的正则api,

一行代码就可以搞定:


public boolean isMatch(String s, String p) {
    return Pattern.compile(p).matcher(s).matches();
}


执行用时:39 ms, 在所有 Java 提交中击败了10.52%的用户

内存消耗:38.4 MB, 在所有 Java 提交中击败了14.85%的用户


解法


如果遇到算法题,还是要从基本的字符串解析入手,一般也不会让用现成的api

这道题采用前面提到过的动态规划思想去解题

难点无非就是找出状态转移方程和确定始值


首选,定义状态dp[i][j]的含义:


对于字符串 s 和字符规律 p,dp[i][j]: 表示s的前i个字符与p的前j个字符是否匹配,结果用boolean类型表示。


然后,确定状态转移方程(公式)


对于字符串s只会是a-z的字符组成

对于字符规律p会分为三种情况


  1. 全是a-z的字符
  2. 除了字符外包含特殊符号“.”
  3. 除了字符外包含特殊符号“*”


对于第一种情况全是字符的情况最简单只要字符相等即可


if(s[i] == p[j]){
  dp[i][j] = dp[i - 1][j - 1]
}else{
  dp[i][j] = false; 
}


对于第二种情况包含特殊字符.时,此时的.代表可以匹配任意一个字符,也就说此处无论s的字符是什么都匹配,然后取决于进一步的判断


dp[i][j] = dp[i - 1][j - 1];


对于第三种情况包含特殊字符*时,此时的* 匹配前面字符的零次或多次

也就是说当出现*时,前面的字符出现或不出现都可以,

*实例化一下,对于s[i]p[j],当p[j]=, 此时必然存在p[j-1],且匹配与否取决于s[i]与p[j-1]


当s[i]与p[j-1]不匹配,此时由于*的存在,相当于p[j-1]p[j]没匹配,直接跳过这两个就可以而且一定要注意p[j-1]一定不能为.不然就不是不匹配了


if(s[i] != p[j-1] && p[j-1] != '.'){
  dp[i][j] = dp[i][j - 2];
}


当s[i]与p[j-1]匹配时,此时要么是s[i]与p[j-1]字符相等(有可能匹配多个s[i-x]= s[i] = p[]j-1),要么是p[j-1]= "."匹配了任意字符(只会是两个)


dp[i][j] = dp[i-1][j] || dp[i][j - 2];


根据思路就可以完成代码实现


public boolean isMatch(String s, String p) {
    boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
    dp[0][0] = true;
    for (int j = 1; j <= p.length(); j++) {
        if (p.charAt(j - 1) == '*') {
            dp[0][j] = dp[0][j - 2];
        }
    }
    for (int i = 1; i <= s.length(); i++) {
        for (int j = 1; j <= p.length(); j++) {
            char si = s.charAt(i - 1), pj = p.charAt(j - 1);
            //全字符场景
            if (Character.isLowerCase(pj)) {
                if (si == pj)
                    dp[i][j] = dp[i - 1][j - 1];
                //包含*    
            } else if (pj == '.') {
                dp[i][j] = dp[i - 1][j - 1];
                //包含.       
            } else {
                char pre_pj = p.charAt(j - 2);
                if (si != pre_pj && pre_pj != '.') {
                    dp[i][j] = dp[i][j - 2];
                } else {
                    dp[i][j] = dp[i - 1][j] || dp[i][j - 2];
                }
            }
        }
    }
    return dp[s.length()][p.length()];
}


小结


动态规划的题目还是挺有规律的,难点就是在找到状态转移方程,然后考虑边界,细心调试就能解出题目,加油!


今天多学一点,明天就少说一句求人的话,加油!


目录
相关文章
|
5月前
|
机器学习/深度学习 人工智能 监控
算法金 | 奇奇怪怪的正则化
**摘要:** 本文深入浅出地介绍了正则化在机器学习中的作用,旨在防止过拟合,提高模型泛化能力。正则化通过添加惩罚项限制模型复杂度,包括L1(Lasso回归,产生稀疏解)、L2(Ridge回归,减少参数大小)、Elastic Net(结合L1和L2优点)以及Lp正则化等。其他方法如Early Stopping、Dropout和数据增强也是防止过拟合的有效手段。选择正则化方法要考虑数据特性、模型复杂性、计算资源和调参能力。正则化参数设置可通过交叉验证、网格搜索等方法优化。文章最后强调了正则化对控制模型复杂度和提升性能的重要性。
68 8
算法金 | 奇奇怪怪的正则化
|
4月前
|
机器学习/深度学习 数据采集 监控
算法金 | DL 骚操作扫盲,神经网络设计与选择、参数初始化与优化、学习率调整与正则化、Loss Function、Bad Gradient
**神经网络与AI学习概览** - 探讨神经网络设计,包括MLP、RNN、CNN,激活函数如ReLU,以及隐藏层设计,强调网络结构与任务匹配。 - 参数初始化与优化涉及Xavier/He初始化,权重和偏置初始化,优化算法如SGD、Adam,针对不同场景选择。 - 学习率调整与正则化,如动态学习率、L1/L2正则化、早停法和Dropout,以改善训练和泛化。
46 0
算法金 | DL 骚操作扫盲,神经网络设计与选择、参数初始化与优化、学习率调整与正则化、Loss Function、Bad Gradient
|
机器学习/深度学习 传感器 算法
多元回归预测 | Matlab麻雀优化算法优化正则化极限学习机(SSA-RELM)回归预测
多元回归预测 | Matlab麻雀优化算法优化正则化极限学习机(SSA-RELM)回归预测
|
机器学习/深度学习 传感器 算法
多元回归预测 | Matlab粒子群优化算法优化正则化极限学习机(PSO-RELM)回归预测
多元回归预测 | Matlab粒子群优化算法优化正则化极限学习机(PSO-RELM)回归预测
|
机器学习/深度学习 算法 数据挖掘
学习笔记: 机器学习经典算法-模型正则化
机器学习经典算法-个人笔记和学习心得分享
148 0
|
JavaScript 算法 前端开发
【前端算法】JS实现数字千分位格式化
JS实现数字千分位格式化的几种思路,以及它们之间的性能比较
346 1
|
存储 前端开发 算法
一行代码解决LeetCode实现 strStr()使用JavaScript解题|前端学算法
一行代码解决LeetCode实现 strStr()使用JavaScript解题|前端学算法
163 0
一行代码解决LeetCode实现 strStr()使用JavaScript解题|前端学算法
一则有趣的算法题:两个栈实现一个队列
一则有趣的算法题:两个栈实现一个队列
|
算法 计算机视觉 Python
Python实现KNN算法和交叉验证
Python实现KNN算法和交叉验证
344 0
Python实现KNN算法和交叉验证
|
算法 数据挖掘 Python
利用python实现Apriori关联规则算法
利用python实现Apriori关联规则算法
670 0
利用python实现Apriori关联规则算法
下一篇
无影云桌面