• 剑指 Offer 19. 正则表达式匹配


     这道题就是有大量的情况需要考虑

    1关于'.'怎么匹配(不考虑*的情况)

    1. bool isMatch(string s, string p) {
    2. int i = 0, j = 0;
    3. while (i < s.size() && j < p.size()) {
    4. // 「.」通配符就是万金油
    5. if (s[i] == p[j] || p[j] == '.') {
    6. // 匹配,接着匹配 s[i+1..] 和 p[j+1..]
    7. i++; j++;
    8. } else {
    9. // 不匹配
    10. return false;
    11. }
    12. }
    13. return i == j;
    14. }

    2考虑带'*'怎么匹配

    1. if (s[i] == p[j] || p[j] == '.') {
    2. // 匹配
    3. if (j < p.size() - 1 && p[j + 1] == '*') {
    4. // 有 * 通配符,可以匹配 0 次或多次
    5. } else {
    6. // 无 * 通配符,老老实实匹配 1 次
    7. i++; j++;
    8. }
    9. } else {
    10. // 不匹配
    11. if (j < p.size() - 1 && p[j + 1] == '*') {
    12. // 有 * 通配符,只能匹配 0 次
    13. } else {
    14. // 无 * 通配符,匹配无法进行下去了
    15. return false;
    16. }
    17. }

    如果匹配,即s[i] == p[j]

    • 1.1p[j]有可能会匹配多个字符,比如s = "aaa", p = "a*",那么p[0]会通过*匹配 3 个字符"a"
    • 1.2p[i]也有可能匹配 0 个字符,比如s = "aa", p = "a*aa",由于后面的字符可以匹配s,所以p[0]只能匹配 0 次。

    如果不匹配,即s[i] != p[j],只有一种情况:

    • p[j]只能匹配 0 次,然后看下一个字符是否能和s[i]匹配。比如说s = "aa", p = "b*aa",此时p[0]只能匹配 0 次
    • 其他情况就是直接返回false,匹配不上

    3 定义dp函数

     boolean helper (String s,int i,String p,int j)

    • 表示s被匹配串从i开始,p匹配串从j开始匹配,如何能够匹配上就返回ture,匹配不上就返回false
    1. bool dp(string& s, int i, string& p, int j) {
    2. if (s[i] == p[j] || p[j] == '.') {
    3. // 匹配
    4. if (j < p.size() - 1 && p[j + 1] == '*') {
    5. // 1.1 通配符匹配 0 次或多次
    6. return dp(s, i, p, j + 2)
    7. || dp(s, i + 1, p, j);
    8. } else {
    9. // 1.2 常规匹配 1 次
    10. return dp(s, i + 1, p, j + 1);
    11. }
    12. } else {
    13. // 不匹配
    14. if (j < p.size() - 1 && p[j + 1] == '*') {
    15. // 2.1 通配符匹配 0 次
    16. return dp(s, i, p, j + 2);
    17. } else {
    18. // 2.2 无法继续匹配
    19. return false;
    20. }
    21. }
    22. }

    1.1通配符匹配0次

     1.1通配符匹配多次

    1.2正常匹配一次 

    2.1这种情况只有*匹配0次可能会匹配成功,跟1.1的匹配0次的情况一样

     2.2如果没有*,直接表示匹配失败

    关于base case的定义

    • 一个 base case 是j == p.size(),按照dp函数的定义,这意味着模式串p已经被匹配完了,那么应该看看文本串s匹配到哪里了,如果s也恰好被匹配完,则说明匹配成功:
    1. if(j==n){
    2. return i==m;
    3. //说明我们的匹配串已经到头了,只有被匹配串也匹配完,才说明匹配上了
    4. }
    • 另一个 base case 是i == s.size(),按照dp函数的定义,这种情况意味着文本串s已经全部被匹配了,那么是不是只要简单地检查一下p是否也匹配完就行了呢?
    1. if(i==m){
    2. //被匹配串走到了尽头,如果我们的匹配串还没有走到尽头,也不一定说匹配不上
    3. //因为还存在一种可以匹配空字符串的可能
    4. if((n-j)%2==1){
    5. return false;
    6. //因为匹配空字符串只有一种可能就是 a* b* c*
    7. //所以能匹配空串的匹配串肯定是偶数的
    8. }
    9. for(;j+12){
    10. if(p.charAt(j+1)!='*'){
    11. return false;
    12. }
    13. }
    14. return true;
    15. }

    最后就是加上一个备忘录,进行记忆化搜索

    1. class Solution {
    2. int dp[][];//1 表示匹配上了 2表示没有匹配上
    3. public boolean isMatch(String s, String p) {
    4. int m=s.length();
    5. int n=p.length();
    6. dp=new int[m+1][n+1];
    7. for(int []arr:dp){
    8. Arrays.fill(arr,-1);
    9. }
    10. return helper(s,0,p,0);
    11. }
    12. public boolean helper (String s,int i,String p,int j){
    13. int m=s.length();
    14. int n=p.length();
    15. if(j==n){
    16. return i==m;
    17. //说明我们的匹配串已经到头了,只有被匹配串也匹配完,才说明匹配上了
    18. }
    19. if(i==m){
    20. //被匹配串走到了尽头,如果我们的匹配串还没有走到尽头,也不一定说匹配不上
    21. //因为还存在一种可以匹配空字符串的可能
    22. if((n-j)%2==1){
    23. return false;
    24. //因为匹配空字符串只有一种可能就是 a* b* c*
    25. //所以能匹配空串的匹配串肯定是偶数的
    26. }
    27. for(;j+12){
    28. if(p.charAt(j+1)!='*'){
    29. return false;
    30. }
    31. }
    32. return true;
    33. }
    34. if(dp[i][j]!=-1){
    35. if(dp[i][j]==1){
    36. return true;
    37. }else{
    38. return false;
    39. }
    40. }
    41. boolean res=false;
    42. if(s.charAt(i)==p.charAt(j)||p.charAt(j)=='.'){
    43. //说明当前字符是匹配上了
    44. if(j1 && p.charAt(j+1)=='*'){
    45. //说明是*匹配,这种匹配上了 可以匹配0次或者多次
    46. res=helper(s,i,p,j+2)||helper(s,i+1,p,j);
    47. }else{
    48. //说明不是*匹配 那么就正常的匹配一次
    49. res=helper(s,i+1,p,j+1);
    50. }
    51. }else{
    52. //说明当前匹配的字符是不匹配的
    53. if(j1&&p.charAt(j+1)=='*'){
    54. //这种情况,只能是匹配0次这种情况
    55. res=helper(s,i,p,j+2);
    56. }else{
    57. res=false;
    58. //这种就直接说明匹配不上
    59. }
    60. }
    61. if(res){
    62. dp[i][j]=1;
    63. }else{
    64. dp[i][j]=2;
    65. }
    66. return res;
    67. }
    68. }

  • 相关阅读:
    Java简单实现图片上传与下载
    Linux帧缓冲注册OLED驱动
    八大排序——快速排序
    数据库顶会 VLDB 2023 论文解读 - Krypton: 字节跳动实时服务分析 SQL 引擎设计
    一、安装GoLang环境和开发工具
    springMVC 导出Excel ,并提供下载(处理日期格式问题)
    智慧码头港口:施工作业安全生产AI视频监管与风险预警平台方案
    【LeetCode热题100】--153.寻找旋转排序数组中的最小值
    docker 安装jenkins 跨域csrf
    【集训DAY N】简单数学【数学】
  • 原文地址:https://blog.csdn.net/qq_50985215/article/details/126822589