题目大意是要求我们实现一个简单的正则表达式全匹配判断。其中正则表达式中只包含一般字符,以及全匹配字符.和变长字符*。其中.可以匹配一个字符,而*与前一个字符相关联,x*可以被看作任意多个x(0到正无穷个)。题目要求我们判断一个字符串是否与正则表达式完全匹配,比如'.*'完全匹配'',但是'a*'不能完全匹配'b'。


这道题目可以用动态规划来解决。记s为待匹配的字符串,n为s的长度,p表示正则表达式字符串,m为p的长度。我们先对p进行一些预处理,将p转换为一般字符串(不包含.和*),但是其中每个字符都拥有两个布尔属性,分别是matchall (是否能匹配所有字符)和flexible (是否可以改变长度)。这可以通过类似下面的方式快速实现:

stk = empty-stack

for(i = 0; i < p.length; i++)

  if(p[i] == '*')

    stk.top.flexible = true

  else

    stk.push(p[i])

    if(p[i] == '.')

      stk.top.matchall = true

p = stk.inner-array

令dp[i][j]表示p[i...]与s[j...]是否完全匹配。dp[i][j]为真,当且仅当下述至少一个条件得到满足:

1.如果p[i].flexible是假,且p[i]能匹配s[j],且dp[i+1][j+1]为真。

2.如果p[i].flexible是真,且dp[i+1][j]为真。

3.如果p[i].flexible是真,且p[i]能匹配s[j],且dp[i][j+1]为真。

这三个条件的充分性非常容易验证,下面仅说明必要性。在dp[i][j]为真的情况下,若p[i]不可扩展,则显然p[i]与s[j]匹配,且p[i+1:m]与s[j+1:n]匹配,这与条件一符合。若p[i]可扩展,那么可以依据p[i]匹配0个字符和多个字符区分,匹配零个字符时,p[i+1:m]与s[j:n]匹配,匹配至少一个字符时有p[i:m]与s[j+1:n]匹配,而者分别落于条件2和条件3中。

利用以上的论述书写我们的代码:

getDp(i, j)

  if(dp[i][j] has been initialized) //如果dp[i][j]已经被初始化过了

    return dp[i][j]

  //处理条件1

  if(p[i].flexible == false)

    dp[i][j] = (p[i].matchall || p[i] == s[j]) && getDp(i+1,j+1)

  //处理条件2和3

  else

    flag = getDp(i + 1, j) || ((p[i].matchall || p[i] == s[j]) && getDp(i, j+1))

  return dp[i][j]

而对于s与p是否最终完全匹配,只需要调用getDp(0, 0)即可得到结果。上述代码中没有处理越界的情况,可以在为dp分配空间时分配额外的边界空间,并在首次调用getDp之前对边界情况做判断。

上述代码的空间复杂度完全取决于dp的大小,故可以认为是O(mn),而由于每次对getDp(i,j)的调用,如果dp[i][j]以及被初始化过了,则费用为O(1),而完全初始化dp的费用为O(nm),因此可以认为getDp(0,0)的时间复杂度为O(mn)。


最后还是老规矩,给出实现代码:

 package cn.dalt.leetcode;

 /**
  * Created by dalt on 2017/6/13.
  */
 public class RegularExpressionMatching {
     byte[][] matchStatuses;
     String text;
     int tlen;
     char[] patternBuf;
     int plen;
     int[] patternExtra;
     final int FLEXIBLE = 1 << 0;
     final int MATCH_ALL = 1 << 1;

     public boolean isMatch(String s, String p) {

         //Precalculate all needed information
         int starCount = 0;
         for (int i = 0, iBound = p.length(); i < iBound; i++) {
             if (p.charAt(i) == '*') {
                 starCount++;
             }
         }
         text = s;
         int validPatternLength = p.length() - starCount;
         patternBuf = new char[validPatternLength];
         patternExtra = new int[validPatternLength];
         int wpos = 0;
         for (int i = 0, iBound = p.length(); i < iBound; i++, wpos++) {
             char ch = p.charAt(i);
             if (ch == '*') {
                 wpos--;
                 patternExtra[wpos] |= FLEXIBLE;
             } else if (ch == '.') {
                 patternExtra[wpos] |= MATCH_ALL;
             } else {
                 patternBuf[wpos] = ch;
             }
         }
         tlen = s.length() + 1;
         plen = validPatternLength + 1;
         matchStatuses = new byte[plen][tlen];
         matchStatuses[plen - 1][tlen - 1] = 1;
         for (int i = 0, iBound = tlen - 1; i < iBound; i++) {
             matchStatuses[validPatternLength][i] = -1;
         }
         for (int i = plen - 2; i >= 0; i--) {
             matchStatuses[i][tlen - 1] = (byte) (matchStatuses[i + 1][tlen - 1] == 1 && (patternExtra[i] & FLEXIBLE) == FLEXIBLE ? 1 : -1);
         }
         return match(0, 0);
     }

     public boolean match(int i, int j) {
         if (matchStatuses[i][j] != 0) {
             return matchStatuses[i][j] == 1;
         }
         boolean flag;
         if ((patternExtra[i] & FLEXIBLE) == 0) {
             flag =  ((patternExtra[i] & MATCH_ALL) == MATCH_ALL || patternBuf[i] == text.charAt(j)) && match(i + 1, j + 1);
         } else {
             boolean matchAllFlag = (patternExtra[i] & MATCH_ALL) == MATCH_ALL;
             flag = match(i + 1, j);
             if (!flag) {
                 flag = (matchAllFlag || patternBuf[i] == text.charAt(j)) && match(i, j + 1);
             }
         }
         matchStatuses[i][j] = (byte)(flag ? 1 : -1);
         return flag;
     }
 }

Leetcode:Regular Expression Matching分析和实现的更多相关文章

  1. [LeetCode] Regular Expression Matching 正则表达式匹配

    Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...

  2. LeetCode | Regular Expression Matching

    Regular Expression Matching Implement regular expression matching with support for '.' and '*'. '.' ...

  3. [leetcode]Regular Expression Matching @ Python

    原题地址:https://oj.leetcode.com/problems/regular-expression-matching/ 题意: Implement regular expression ...

  4. [LeetCode] Regular Expression Matching(递归)

    Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...

  5. [LeetCode] Regular Expression Matching [6]

    称号: Implement regular expression matching with support for '.' and '*'. '.' Matches any single chara ...

  6. LeetCode——Regular Expression Matching

    Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...

  7. LeetCode Regular Expression Matching 网上一个不错的实现(非递归)

    '.' Matches any single character.'*' Matches zero or more of the preceding element. The matching sho ...

  8. LeetCode: Regular Expression Matching 解题报告

    Roman to IntegerGiven a roman numeral, convert it to an integer. Input is guaranteed to be within th ...

  9. lc面试准备:Regular Expression Matching

    1 题目 Implement regular expression matching with support for '.' and '*'. '.' Matches any single char ...

随机推荐

  1. 解放内存之搭建自己的 R Server

    学校的课五门有四门需要跑R程序,有一些长长长的代码实在是占用了太多的内存,果断决定搭个R的服务器放着自己跑. 愉快的是,R studio server 的搭建真心简单快捷~这个从前被我忽略的东东终于排 ...

  2. poj 1952 最长公共子序列计数

    看代码就懂了  不解释  3 1 1 1 1 2 2 2 1 1 1 3  第一个3 和最后一个 3 只需要一个就够了,,, #include<iostream> #include< ...

  3. 使用JspSmart文件上传

    index.html [html] view plaincopy     <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transition ...

  4. Robot Framework接口测试(4)

    现在我们已经做好了进行接口测试的必要准备:1.拼接发送的报文:2.发送报文的方法.现在我们实现RF上的接口测试. 我们先对发送的方法进行一下封装: 1.拼接报文方法: #coding : utf-8 ...

  5. 前端工程师面试问题归纳(一、问答类html/css/js基础)

    一.参考资源 1.前端面试题及答案整理(一) 2.2017年前端面试题整理汇总100题 3.2018最新Web前端经典面试试题及答案 4.[javascript常见面试题]常见前端面试题及答案 5.W ...

  6. Django的CSRF机制

    原文链接:http://www.cnblogs.com/lins05/archive/2012/12/02/2797996.html 必须有的是: 1.每次初始化一个项目时,都能看到django.mi ...

  7. 向HDFS中追加内容

    向生成好的hdfs文件中追加内容,但是线上使用的版本是1.0.3,查看官方文档发现,在1.0.4版本以后才支持文件append 以下是向hdfs中追加信息的操作方法 如果你只在某一个driver中追加 ...

  8. hadoop之 Zookeeper 分布式应用程序协调服务

    (1) Zookeeper 在 Hadoop 集群中的作用 Zookeeper 是分布式管理协作框架,Zookeeper 集群用来保证 Hadoop 集群的高可用,(高可用的含义是:集群中就算有一部分 ...

  9. 数据科学:numpy.where() 的用法

    原文出处:numpy.where() 用法讲解 原创作者:massquantity numpy.where() 有两种用法: 1. np.where(condition, x, y) 满足条件(con ...

  10. org/apache/hadoop/hbase/mapreduce/TableReducer:Unsupported major.minor version52.0

    问题详情: 问题原因: <dependency>    <groupId>org.apache.hbase</groupId>    <artifactId& ...