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];
        }
  • 相关阅读:
    51nod乘积之和
    Dell服务器安装OpenManage(OMSA)
    Nginx反向代理PHP
    搭建haproxy
    108. Convert Sorted Array to Binary Search Tree
    60. Permutation Sequence
    142. Linked List Cycle II
    129. Sum Root to Leaf Numbers
    118. Pascal's Triangle
    26. Remove Duplicates from Sorted Array
  • 原文地址:https://www.cnblogs.com/helloworldcode/p/11649837.html
Copyright © 2011-2022 走看看