zoukankan      html  css  js  c++  java
  • [Leetcode]10. 正则表达式匹配

    题目描述

    给你一个字符串 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
    
    • 提示:
    0 <= s.length <= 20
    0 <= p.length <= 30
    s 可能为空,且只包含从 a-z 的小写字母。
    p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
    保证每次出现字符 * 时,前面都匹配到有效的字符
    

    第一种解法(递归)

    class Solution2 {
    
      public boolean isMatch(String s, String p) {
        if (p.length() == 0) {
          return s.length() == 0;
        }
        if (p.length() > 1 && p.charAt(1) == '*') {
          //aaa a*
          //*匹配0次a或1次a
          return isMatch(s, p.substring(2)) ||
              (s.length() != 0 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.')
                  && isMatch(s.substring(1), p));
        } else {
          //aaa aa.
          //第一个字符相等,继续匹配之后的
          return (s.length() != 0 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.') && isMatch(
              s.substring(1), p.substring(1)));
        }
      }
    
      public static void main(String[] args) {
        System.out.println(new Solution2().isMatch("aa", "a"));
        System.out.println(new Solution2().isMatch("aa", "a*"));
        System.out.println(new Solution2().isMatch("aa", "a."));
        System.out.println(new Solution2().isMatch("ab", ".*"));
        System.out.println(new Solution2().isMatch("aab", "c*a*b"));
      }
    }
    

    第二种解法(递归+记忆化)

    class Solution4 {
    
      public boolean isMatch(String s, String p) {
        Boolean[][] memo = new Boolean[s.length() + 1][p.length() + 1];
        return isMatch(s, 0, p, 0, memo);
      }
    
      private boolean isMatch(String s, int sStart, String p, int pStart, Boolean[][] memo) {
        if (pStart >= p.length()) {
          return sStart >= s.length();
        }
        if (memo[sStart][pStart] == null) {
          boolean res;
          //p剩余长度大于1,且从pStart开始第二个字符为*
          if (p.length() - pStart > 1 && p.charAt(pStart + 1) == '*') {
            //*匹配0次前面的字符
            if (isMatch(s, sStart, p, pStart + 2, memo)) {
              res = true;
            } else {
              //s字符串遍历结束了
              if (sStart >= s.length()) {
                res = false;
              } else {
                //匹配s结尾的一个字符,继续匹配下一个字符
                res = match(s, sStart, p, pStart) && isMatch(s, sStart + 1, p, pStart, memo);
              }
            }
          } else {
            if (sStart >= s.length()) {
              res = false;
            } else {
              res = match(s, sStart, p, pStart) && isMatch(s, sStart + 1, p, pStart + 1, memo);
            }
          }
          memo[sStart][pStart] = res;
        }
        return memo[sStart][pStart];
      }
    
      private boolean match(String s, int sStart, String p, int pStart) {
        char pChar = p.charAt(pStart);
        char sChar = s.charAt(sStart);
        return pChar == '.' || pChar == sChar;
      }
    
      public static void main(String[] args) {
        System.out.println(new Solution4().isMatch("aa", "a"));
        System.out.println(new Solution4().isMatch("aa", "a*"));
        System.out.println(new Solution4().isMatch("aa", "a."));
        System.out.println(new Solution4().isMatch("ab", ".*"));
        System.out.println(new Solution4().isMatch("aab", "c*a*b"));
      }
    }
    

    和第一种方法类似,加上了记录每个字符串下标的查询结果。

    动态规划

    class Solution {
    
      public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[][] memo = new boolean[m + 1][n + 1];
        //表示空串和空串匹配
        memo[0][0] = true;
        for (int i = 0; i <= m; i++) {
          for (int j = 1; j <= n; j++) {
            if (p.charAt(j - 1) == '*') {
              //匹配0次
              memo[i][j] = memo[i][j - 2];
              //匹配1次
              if (match(s, i, p, j - 1)) {
                memo[i][j] = memo[i][j] || memo[i - 1][j];
              }
            } else {
              if (match(s, i, p, j)) {
                memo[i][j] = memo[i - 1][j - 1];
              }
            }
          }
        }
        return memo[m][n];
      }
    
      public boolean match(String s, int i, String p, int j) {
        if (i == 0) {
          return false;
        }
        char pChar = p.charAt(j - 1);
        char sChar = s.charAt(i - 1);
        return pChar == '.' || pChar == sChar;
      }
    
      public static void main(String[] args) {
        System.out.println(new Solution().isMatch("aa", "a"));
        System.out.println(new Solution().isMatch("aa", "a*"));
        System.out.println(new Solution().isMatch("aa", "a."));
        System.out.println(new Solution().isMatch("ab", ".*"));
        System.out.println(new Solution().isMatch("aab", "c*a*b"));
      }
    }
    
  • 相关阅读:
    Go 语言简介(下)— 特性
    Array.length vs Array.prototype.length
    【转】javascript Object使用Array的方法
    【转】大话程序猿眼里的高并发架构
    【转】The magic behind array length property
    【转】Build Your own Simplified AngularJS in 200 Lines of JavaScript
    【转】在 2016 年做 PHP 开发是一种什么样的体验?(一)
    【转】大话程序猿眼里的高并发
    php通过token验证表单重复提交
    windows 杀进程软件
  • 原文地址:https://www.cnblogs.com/strongmore/p/14477636.html
Copyright © 2011-2022 走看看