1. 程式人生 > >[LeetCode]10. Regular Expression Matching正則表示式匹配

[LeetCode]10. Regular Expression Matching正則表示式匹配

Given an input string (s) and a pattern (p), 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).

Note:

    s could be empty and contains only lowercase letters a-z.
    p could be empty and contains only lowercase letters a-z, and characters like . or *.

Example 1:

Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".

Example 2:

Input:
s = "aa"
p = "a*"
Output: true
Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".

Example 3:

Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".

Example 4:

Input:
s = "aab"
p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".

Example 5:

Input:
s = "mississippi"
p = "mis*is*p*."
Output: false

題目要求判斷給出的表示式p能否匹配字串s,其中"."能匹配任意字元,"*"能匹配前一個字元任意多次,比如"a*",可以匹配空字元,或者任意多個a,基於本題中
"*"可以是0個,所以不能由前面不匹配就得出後面也不匹配的結論,比如s=b,p=a*b,一開始a!=b,我們不能由這個結論得出整個字串不匹配,所以這題我們需要把整個字串匹配完。

這題我的做法是DP,假設dp[i][j]表示匹配到S[:i]與P[:j]
(1)p[j]=!'*',此時p[j]可能是字元,那就需要S[i]==P[j],可能是".",肯定匹配
dp[i][j] = dp[i-1][j-1] && ( s[i]==p[j] || p[j]=='.' )

(2)P[j]=='*',此時需要根據*的重複次數分情況討論
          1)重複0次,此時p[j]的作用就是消去前一個字元的作用,所以dp[i][j] = dp[i][j-2]
          2)重複1次或以上,需要看p[j-1]的這個字元能否匹配S[i]這個位置的字元,
也就是S[i]==P[j-1]&&P[j-1]=='.',再來看dp[i][j]是從哪一個狀態轉化來的,假設
S=abbbb,p=ab*,要求dp[1][1]時,此時dp[0][]已經全部得出來了,dp[1][1]=dp[0][1],
dp[0][1]到dp[1][1]是"*"從重複0次到1次的變化,然後是dp[2][2]=dp[1][2],我們可以總結出,
dp[i][j]的狀態是"*"重複次數增加帶來的狀態變化,變化前是dp[i-1][j],也就是"*"重複次數增加前的狀態。所以dp[i][j] = dp[i-1][j] && ( S[i]==P[j-1] || P[j-1]=='.' )

綜上所述
dp[i][j] = dp[i-1][j-1] && ( s[i]==p[j] || p[j]=='.' ) ,條件是p[j]=!'*'
dp[i][j] = dp[i][j-2],條件是P[j]=='*',並且重複0次
dp[i][j] = dp[i-1][j] && ( S[i]==P[j-1] || P[j-1]=='.' ),條件是P[j]=='*'並重復不止1次

因為存在i-1,j-2這樣的狀態,為了防止陣列越界,我們把S和P都向後移動一個位置,就當添加了一個空格" "進去,這樣S和P的比較都是從1開始了,所有的判斷條件需要多減一位

同時,簡化"*"重複次數的不同狀態,因為"*"重複0次不需要任何條件,dp[i][j] = dp[i][j - 2] || i > 0 && dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.')

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length(), n = p.length();
        boolean dp[][] = new
boolean[m + 1][n + 1]; dp[0][0] = true; for(int i = 0; i <= m; ++i) { for(int j = 1; j <= n; ++j) { if(p.charAt(j - 1) == '*') { dp[i][j] = dp[i][j - 2] || i > 0 && dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.'); }
else { dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.'); } } } return dp[m][n]; } }