[LeetCode 10] Regular Expression Matching

Implement regular expression matching with support for '.' and '*'.

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

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)
Example
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true


For s[0 ~ i] and p[0 ~ j], we have the following cases.

1. s[i] == p[j] or p[j] == '.' ,   reduce the problem to s[0 ~ i - 1] and p[0 ~ j - 1];

2. p[j] == '*', 

 a.  s[i] == p[j - 1] or p[j - 1] == '.'   : reduce to s[0 ~ i] and p[0 ~ j - 2] for 0 occurence of p[j - 1];  or reduce to s[0 ~ i - 1] and p[0 ~ j] for 1 occurence of p[j - 1].

    b.  s[i] != p[j - 1] :  reduce to s[0 ~ i] and p[0 ~ j - 2] for 0 occurence of p[j - 1].

3. all other cases s and p do not match. 

 

We can solve this problem based the above analysis both recursively and by dynamic programming. 

Solution 1. Recursion

 1 public class RegularExpressionMatching {
 2     public boolean isMatchRecursion(String str, String pattern) {
 3         if(str == null || pattern == null) {
 4             return false;
 5         }
 6         String newPattern = pattern.replaceAll("(\\*){2,}", "*"); 
 7         return matchHelper(str, str.length() - 1, newPattern, newPattern.length() - 1);
 8     }
 9     private boolean matchHelper(String str, int idx1, String pattern, int idx2) {
10         if(idx1 < 0 && idx2 < 0 || idx1 < 0 && idx2 <= 1 && pattern.charAt(idx2) == '*') {
11             return true;
12         }
13         else if(idx1 < 0 && idx2 >= 0 || idx1 >= 0 && idx2 < 0) {
14             return false;
15         }
16         if(pattern.charAt(idx2) == '.' || str.charAt(idx1) == pattern.charAt(idx2)) {
17             return matchHelper(str, idx1 - 1, pattern, idx2 - 1);
18         }
19         else if(pattern.charAt(idx2) == '*') {
20             if(idx2 > 0 && (pattern.charAt(idx2 - 1) == str.charAt(idx1) || pattern.charAt(idx2 - 1) == '.')) {
21                 return matchHelper(str, idx1, pattern, idx2 - 2) || matchHelper(str, idx1 - 1, pattern, idx2);
22             }
23             else {
24                 return matchHelper(str, idx1, pattern, idx2 - 2);
25             }
26         }
27         return false;
28     }
29     public static void main(String[] args) {
30         RegularExpressionMatching test = new RegularExpressionMatching();
31         System.out.println(test.isMatchRecursion("", ""));    //true
32         System.out.println(test.isMatchRecursion("", "*"));    //true
33         System.out.println(test.isMatchRecursion("aa", "a"));    //false
34         System.out.println(test.isMatchRecursion("aa", "aa"));    //true
35         System.out.println(test.isMatchRecursion("aaa", "aa"));    //false
36         System.out.println(test.isMatchRecursion("aa", "*"));    //false
37         System.out.println(test.isMatchRecursion("aa", "**"));    //false
38         System.out.println(test.isMatchRecursion("aa", "a*"));    //true
39         System.out.println(test.isMatchRecursion("ab", ".*"));    //true
40         System.out.println(test.isMatchRecursion("aab", "*a.b"));    //true        
41     }
42 }

 

Solution 2. Dynamic Programming 

Initialization: 

T[0][0] = true;  When both s and p are empty string, the match result should return true.

When s is empty, there is also another case of p that matches the empty string.  If each letter a-z or . is followed by *, like a*b*c*, then taking 0 occurence of each letter matches empty string.

 1 public boolean isMatchDp(String str, String pattern) {
 2     if(str == null || pattern == null) {
 3         return false;
 4     }
 5     String newPattern = pattern.replaceAll("(\\*){2,}", "*"); 
 6     boolean[][] T = new boolean[str.length() + 1][newPattern.length() + 1];
 7     T[0][0] = true;
 8     for(int i = 1; i <= newPattern.length(); i++) {
 9         if(i == 1 && newPattern.charAt(i - 1) == '*') {
10             T[0][i] = true;
11         }
12         else if(newPattern.charAt(i - 1) == '*') {
13             T[0][i] = T[0][i - 2];
14         }
15     }
16     for(int i = 1; i <= str.length(); i++) {
17         for(int j = 1; j <= newPattern.length(); j++) {
18             if(str.charAt(i - 1) == newPattern.charAt(j - 1) || newPattern.charAt(j - 1) == '.') {
19                 T[i][j] = T[i - 1][j - 1];
20             }
21             else if(newPattern.charAt(j - 1) == '*') {
22                 if(j == 1) {
23                     T[i][j] = false;
24                 }
25                 else {
26                     T[i][j] = T[i][j - 2];
27                     if(str.charAt(i - 1) == newPattern.charAt(j - 2) || newPattern.charAt(j - 2) == '.'){
28                         T[i][j] |= T[i - 1][j];
29                     }
30                 }
31             }
32             else {
33                 T[i][j] = false;
34             }
35         }
36     }
37     return T[str.length()][newPattern.length()];
38 }

 

 

Related Problems 

Wildcard Matching



posted @ 2017-08-29 13:35  Review->Improve  阅读(339)  评论(0编辑  收藏  举报