Showing posts with label dp. Show all posts
Showing posts with label dp. Show all posts

Sunday, January 8, 2017

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)

Some examples:
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


/*
dp[i][j] == true: the substring from 0 to index i of string s can match with the substring from 0 to index j of string p

When we compute each dp[i][j], there are four conditions:
1. p.charAt(j-1) == s.charAt(i-1)    
    --> dp[i][j] = dp[i - 1][j - 1];
2. p.charAt(j-1) == '.'                     
    --> dp[i][j] = dp[i - 1][j - 1];
3. p.charAt(j-1) == '*' 
   • p.charAt(j-2) == s.charAt(i-1) or p.charAt(j-2) == '.'
    --> dp[i][j] = dp[i][j - 1] ||   //a* counts as single a
                   dp[i][j - 2] ||   //a* counts as empty
                   dp[i - 1][j]      //a* counts as multiple a
   • else 
    --> dp[i][j] = dp[i][j - 2]      //a* counts as empty
4. else
    --> dp[i][j] = false

Notice the initialization in this problem.

Notice the special case:
1. s = "", p = "*a", return false;
2. s = "", p = "**", return true;

time:O(m*n), space:O(m*n)
*/


public class Solution {
    public boolean isMatch(String s, String p) {
        if (s == null && p == null) {
            return true;
        }
        if (s == null || p == null) {
            return false;
        }
        int sl = s.length();
        int pl = p.length();
        //match[x][y]: s.substring(0,x) matches p.substring(0,y)
        boolean[][] match = new boolean[sl + 1][pl + 1]; 
        match[0][0] = true;
        for (int j = 2; j <= pl; j++) {
            if (p.charAt(j - 1) == '*') {
                match[0][j] = match[0][j - 2];  //match[0][1] must be false;
            }
        }
        for (int i = 1; i <= sl; i++) {
            for (int j = 1; j <= pl; j++) {
                if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') {
                    match[i][j] = match[i - 1][j - 1];
                } 
                else if (p.charAt(j - 1) == '*') {
                    if (j - 2 < 0) {
                        continue;
                    }
                    if (s.charAt(i - 1) != p.charAt(j - 2) && 
                        p.charAt(j - 2) != '.') {
                        match[i][j] = match[i][j - 2];
                    } else {
                        match[i][j] = match[i][j - 2] || match[i][j - 1] || 
                                      match[i - 1][j];
                    }
                }
            }
        }
        return match[sl][pl];
    }
}