zoukankan      html  css  js  c++  java
  • LeetCode正则表达式匹配

    题目描述

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

    '.' 匹配任意单个字符
    '*' 匹配零个或多个前面的那一个元素

      所谓匹配,是要涵盖 整个字符串 s的,而不是部分字符串。

    说明:

      s 可能为空,且只包含从 a-z 的小写字母。
      p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
    示例 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"。


    1. 回溯法

      当问题简单的时候,假设题中就单纯的是两个普通的字符串的匹配,可以采用下面的方法去匹配

     public boolean isMatch(String s, String p) {
         if(p.isEmpty())
             return s.isEmpty();
         boolean first_flag = !s.isEmpty() && s.charAt(0) == p.charAt(0);
         return first_flag && isMatch(s.substring(1), p.substring(1));
     }

      此时慢慢对问题进行复杂化,如果加上一个.b表示可匹配零个或多个任意字符,则变成了如下形式:

     public boolean isMatch(String s, String p) {
         if(p.isEmpty())
         return s.isEmpty();
         boolean first_flag = !s.isEmpty() && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.');
         return first_flag && isMatch(s.substring(1), p.substring(1));
     }

      继续对问题复杂化,加入*,代表可以匹配零个或多个前面的那一个元素,这个时候要改变的是后面的递归方式了,要注意的是*可能出现在模式串p的第二个位置(不可能是第一个位置),如果当前字符串p的第二个位置是*,则采用回溯的办法——一直将模式串的*去匹配字符串,一旦出现问题就返回上一层解空间,将模式串去掉两个字符(x*:x表示任意字符),如下

    public boolean isMatch(String s, String p) {
        if(p.isEmpty())
            return s.isEmpty();
        boolean first_flag = !s.isEmpty() && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.');
        if( p.length() >= 2 && p.charAt(1) == '*'){
            return first_flag && isMatch(s.substring(1), p) || isMatch(s, p.substring(2));
        }else
            return first_flag && isMatch(s.substring(1), p.substring(1));
    }

    2. 动态规划

      dp[i][j]表示字符串s的子串s[0....i-1]和模式串的子串p[0...j-1]是否匹配,匹配为1,不匹配则为0,那么:

      1. p[j-1] != '*' 时,此时只要判断s[i-1]和p[j-1]是否相等同时和上一个dp[i-1][j-1]相与即可,且这个比较要发生在i>0的时候,即:

    if(p[j-1] != '*' `)
        dp[i][j] = i>0 && dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] = '.')
    1. p[j-1] == '*'时,如果这个*并没有重复前面那个字符,比如aabc*a*b,此时模式串c和后面的*没有重复,则dp[i][j]=dp[i][j-2];如果相反,如果这个*重复前面那个字符,比如aaba*b,则dp[i][j]=dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] =='*')

    if(p[j-1] == '*' `)
        dp[i][j] = dp[i][j - 2] || (i > 0 && (s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]);

    综上可知:

    public boolean isMatch(String s, String p) {
            int m = s.length();
            int n = p.length();
            boolean[][] dp = new boolean[m+1][n+1];
            boolean[] sss  = new boolean[n+1];
            Arrays.fill(sss,false);
            Arrays.fill(dp, sss);
            dp[0][0] = true;
            for (int i = 0; i <= m; i++)
                for (int j = 1; j <= n; j++)
                    if ( p.charAt(j-1) == '*')
                        dp[i][j] = dp[i][j - 2] || (i > 0 && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j-2) == '.') && dp[i - 1][j]);
                    else dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.');
            return dp[m][n];
        }
  • 相关阅读:
    UI- 基础控件零散知识点回归
    UI-定时器与动画使用总结
    IE浏览器url中带中文报错的问题;以及各种兼容以及浏览器问题总结
    java实现判断一个经纬度坐标是否在一个多边形内(经自己亲测)
    高德地图web端笔记;发送http请求的工具类
    高德地图JSapi
    shiro(三),使用第三方jdbcRealm连接数据库操作
    shiro(二)自定义realm,模拟数据库查询验证
    java安全框架shiro(一)
    解决celipse中mybatis使用的时候xml没有提示的问题
  • 原文地址:https://www.cnblogs.com/helloworldcode/p/11649837.html
Copyright © 2011-2022 走看看