lintcode154 - Regular Expression Matching - hard

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(string s, string 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") → trueexpress

 

DP。 O(m*n), m爲string長度,n爲pattern長度
1.定義:dp[i][j]是s.substring(0, i)和p.substring(0, j)是否爲匹配對,從頭開始對比。
2.狀態轉移方程:
a)dp[i][j] = dp[i - 1][j - 1]; 在兩個字符相等或p的字符爲’.’時。(從左上來)
b)dp[i][j] = dp[i][j - 2] || (dp[i - 1][j] && (p[j - 1] == s[i] || p[j - 1] == ‘.')); 在p的字符爲’*’時,並且其中一種狀況須要*前面的那個字符得是’.’或者和s當前字符相同。(從上一格來和從左兩格來)
c)dp[i][j] = false; 其餘狀況,其實也就是兩個字符不相同並且p的不是特殊字符時。
3.初始化:dp[0][0]=true, 第一行也就是聲明空s」"是否匹配一段段pattern的時候,若是遇到p.c ==‘*’的狀況,要取左邊兩格的值(讓a*或者.*什麼的此時表示爲空,從而保證」"能匹配上a*,a*b*,a*b*.*這些pattern)。第一列也就是聲明空p是否匹配一段段的string,確定都是false啊。
4.刷新方向,自上而下,從左到右。
5.具體解釋:
2a)在字符串相等或者’?’被迫匹配到s的當前字符的時候,當前位置合格了,你得把這兩個字符擦掉看前面的合格不合格。
2b)dp[i][j - 2]就是說把a*這種當作空的,若是看空了是true的那確定能借鑑過來。
dp[i - 1][j]就是把a*這種當作1個或多個a,這樣你就要把s裏那個匹配上的a給吞掉,可是j不改變讓a*保留,由於後續對比a*說不定還能夠發揮用途繼續吞,有沒有進一步表明那是dp[i-1][j]幫你去判斷的事。值得注意的是這時候能吞的狀況必需要*前的那個字母符合吞吞條件呀,因此必定要和當前s[i]相同或者是萬能吞吞符’.’。
2c)普通字符當前位置都匹配不上那就不可能了,你整個字符串宏觀看,最後一個是普通字符並且不同的話,前面的*?再怎麼巧妙也解決不了最後不一樣的問題啊。數組

細節:
1.題意:a*這種是能夠表示0,1,n個a。.*這種事能夠表示0,1,n個.,因此能夠變造成不一樣的字母如.*==ab。
2.數組大小是[s.length()+1][p.length()+1],留出上左的行列給初始化的。因此給數組賦值的下標和取substring的下標有一個offset,要當心。因此正式part循環是[1, length()],取char是substring(i - 1)。spa

參考視頻:https://www.youtube.com/watch?v=l3hda49XcDE&t=194sprototype

 

實現:code

public class Solution {
    /**
     * @param s: A string 
     * @param p: A string includes "." and "*"
     * @return: A boolean
     */
    public boolean isMatch(String s, String p) {
        // write your code here
        
        boolean[][] isMatch = new boolean[s.length() + 1][p.length() + 1];
        isMatch[0][0] = true;
        
        for (int j = 1; j <= p.length(); j++) {
            if (p.charAt(j - 1) == '*' && j >= 2) {
                isMatch[0][j] = isMatch[0][j - 2];
            }
        }
        
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= p.length(); j++) {
                if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') {
                    isMatch[i][j] = isMatch[i - 1][j - 1];
                } else if (p.charAt(j - 1) == '*') {
                    if (j < 2) {
                        continue;
                    }
                    // 試試可能a*表示爲empty的時候你就成功了。
                    isMatch[i][j] = isMatch[i][j - 2];
                    // 當a*表示爲一次或屢次時,你還有一次額外成功的機會。
                    if (p.charAt(j - 2) == s.charAt(i - 1) || p.charAt(j - 2) == '.')  {
                        isMatch[i][j] = isMatch[i][j] || isMatch[i - 1][j];
                    }
                }
            }
        }
        return isMatch[s.length()][p.length()];
        
    }
}
相關文章
相關標籤/搜索