Leetcode:Regular Expression Matching分析和实现
题目大意是要求我们实现一个简单的正则表达式全匹配判断。其中正则表达式中只包含一般字符,以及全匹配字符.和变长字符*。其中.可以匹配一个字符,而*与前一个字符相关联,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分析和实现的更多相关文章
- [LeetCode] Regular Expression Matching 正则表达式匹配
Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...
- LeetCode | Regular Expression Matching
Regular Expression Matching Implement regular expression matching with support for '.' and '*'. '.' ...
- [leetcode]Regular Expression Matching @ Python
原题地址:https://oj.leetcode.com/problems/regular-expression-matching/ 题意: Implement regular expression ...
- [LeetCode] Regular Expression Matching(递归)
Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...
- [LeetCode] Regular Expression Matching [6]
称号: Implement regular expression matching with support for '.' and '*'. '.' Matches any single chara ...
- LeetCode——Regular Expression Matching
Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...
- LeetCode Regular Expression Matching 网上一个不错的实现(非递归)
'.' Matches any single character.'*' Matches zero or more of the preceding element. The matching sho ...
- LeetCode: Regular Expression Matching 解题报告
Roman to IntegerGiven a roman numeral, convert it to an integer. Input is guaranteed to be within th ...
- lc面试准备:Regular Expression Matching
1 题目 Implement regular expression matching with support for '.' and '*'. '.' Matches any single char ...
随机推荐
- 【ES6】箭头函数
let getPrices = () => 4.55 console.log(getPrices()) let arr = ['apple', 'banana', 'orange'] arr.f ...
- 21天学通C++_Day2
继续学习,今天满课,相对学习内容较少,下面罗列内容: 0.常量 ▪字面常量: ▪使用关键字const声明的常量,const double Pi = 22.0/7; //后面有分号,跟定义变量一样 ▪使 ...
- codechef Graph on a Table
codechef Graph on a Table https://www.codechef.com/problems/TBGRAPH 题意 : 一个\(n\times m\)的网格图.\(q\) 个 ...
- 学大伟业DAY2模拟赛
T1忍者钩爪 题目描述 小Q是一名酷爱钩爪的忍者,最喜欢飞檐走壁的感觉,有一天小Q发现一个练习使用钩爪的好地方,决定在这里大显身手. 场景的天花板可以被描述为一个无穷长的数轴,初始小Q挂在原点上.数轴 ...
- 缓存(Cache)管理 ---- 系列文章
利用Cache防止同一帐号重复登录 .net中Cache管理操作 系统缓存全解析 (下) 系统缓存全解析 (中) 系统缓存全解析 (上) 出处:http://www.cnblogs.com/luckd ...
- 【ASP.NET Web API2】Digest认证
Digest摘要认证 对于Basic认证方案来说,被传输的认证凭证仅仅采用Base64编码,所以包含密码的认证凭证基本上可以视为明文传输.Digest认证在此基础上进行了改善,在一定程度上提高了安全系 ...
- 5 数组 Swift/Object-C ——《Swift3.0从入门到出家》
Swift中数组是一种数据结构,用来存放多个形同类型的数据结构,数据在数组内的存放是有序的,存进来的数据个读出来的顺序相同 Object-C 中数组能够存放任意类型的数据类型为[AnyObject] ...
- Memcached的限制和使用建议
1. 在Memcached中可以保存item数据量没有限制的,只要内存足够 2. Memcached单进程最大使用内存2G,要使用更多内存,可以分多个端口开启多个Memcached进程 3. Memc ...
- linux 下SPI通信注意事项(待续)
一.2台Linux设备之间使用SPI通信 1.标准Linux只支持Master 模式.但是可以在驱动中修改为Slave模式: 2.硬件SPI可能支持Slave模式,也可能不支持.这个要提前确认好: 3 ...
- 批处理判断是否有.net环境
@echo off (echo 已安装.NET Framework) else (echo 未安装.NET Framework) pause>nul