剑指OFFER笔记_19_正则表达式匹配_JAVA实现
题目:正则表达式匹配
- 请实现一个函数用来匹配包含’.‘和’*‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
解题思路
- 此题可以利用动态规划法。因为它满足应用动态规划法的两个必要条件,一个是可以划分为比较小的问题,使其容易求解;二是可以将答案重新组合起来形成最终的答案。
- 本题可以采用从后往前缩小和从前往后缩小范围两种。我采用了从后往前。
- 首先检测string和pattern的最后一位。此时有三种情况:
- pattern的最后一位为字母。这是一种简单情况,只需要去使其和string最后一位作比较。若相同,则string和pattern将长度减1,继续检测之前的部分是否匹配,若不同,直接返回false。
- pattern的最后一位为’.’。这也是一种简单情况,只需要string还有字符去匹配就也可以分别将长度减1,继续检测。
- pattern的最后一位为’*’。这种情况下,‘*’需要分三种情况去看待。
1. ‘*‘前的元素匹配了0次。此时将string的下标上限不变,pattern的下标上限-2,略过’*’,继续检测。
2. ‘*‘前的元素匹配了1次。此时将string的下标上限减1,pattern的下标上限-2,略过’*’,继续检测。
3. '*'前的元素匹配了超过1次。此时将string的下标上限减1,pattern的下标上限不变,继续检测。
- 在加上一些边界情况的判断即可以写出代码了。
代码
函数主体部分代码
package q19;
public class Solution {
public boolean isMatch(String s, String p) {
if (s == null || p == null)
{
return false;
}
if (s.length() == 0 && p.length() == 0)
{
return true;
}
char[] schar = s.toCharArray();
char[] pchar = p.toCharArray();
return Match(schar, pchar, schar.length-1, pchar.length-1);
}
public boolean Match(char[] string, char[] pattern, int sindex, int pindex)
{
//若字符串和模式全部消除,则返回true
if (sindex <= -1 && pindex <= -1)
{
return true;
}
//若字符串未全部消除,模式已经全部消除,返回false
if (sindex > -1 && pindex <= -1)
{
return false;
}
//若字符串已全部消除,模式未全部消除,单独考虑
if (sindex <= -1 && pindex > -1)
{
return checkPatternForEmptyString(pattern, pindex);
}
//字符串和模式都有剩余的情况。
//若模式结尾是字母,检测与字符串结尾是否匹配,不匹配返回false,匹配则递归调用,index同时减1
if (pattern[pindex] != '.' && pattern[pindex] != '*')
{
if (string[sindex] != pattern[pindex])
{
return false;
}
return Match(string, pattern, sindex-1, pindex-1);
}
//若模式结尾是'.',任意情况都可以index同时减1
if (pattern[pindex] == '.')
{
return Match(string, pattern, sindex-1, pindex-1);
}
if (pattern[pindex] == '*')
{
//若可以匹配上,分两种情况
if (string[sindex] == pattern[pindex-1] || pattern[pindex-1] == '.')
{
return Match(string, pattern, sindex-1, pindex) ||
Match(string, pattern, sindex-1, pindex-2) ||
Match(string, pattern, sindex, pindex-2);
}
//若匹配不上,则视'*'为0次
else
{
return Match(string, pattern, sindex, pindex-2);
}
}
return false;
}
/**
* 此函数检测此段模式是否可以匹配空字符串
* @param pattern 模式
* @param pindex 此段模式的下标上限
* @return 若能匹配空字符串,返回true。若不能,返回false。
*/
public boolean checkPatternForEmptyString(char[] pattern, int pindex)
{
//只有当pattern中是.*或a*的组合时才能返回true
for (int i = 0; i <= pindex; i++)
{
if (pattern[i] != '*')
{
//最后一位必须是*,否则不可能匹配空字符串
if (i == pindex)
{
return false;
}else
{
if (pattern[i+1] != '*')
{
return false;
}
}
}
}
return true;
}
}
测试部分代码
package q19;
public class TestApp {
public static void main(String[] args) {
Solution s = new Solution();
String[] str = new String[5];
String[] pat = new String[5];
//false
str[0] = "aa";
pat[0] = "a";
//true
str[1] = "aa";
pat[1] = "a*";
//true
str[2] = "ab";
pat[2] = ".*";
//true
str[3] = "aab";
pat[3] = "c*a*b";
//false
str[4] = "mississippi";
pat[4] = "mis*is*p*";
for (int i = 0; i < 5; i++) {
System.out.println(s.isMatch(str[i], pat[i]));
}
}
}
运行结果截图
LeetCode运行截图