preface
Today I did a dynamic programming problem, Letcode regular expression matching, share the solution of the problem
10. Regular expression matching
Train of thought
So this looks like a dynamic program, or a recursive solution, but the recursion would take too long.
The overall idea is as follows:
-
First, the regular expression string P is converted into data pList, and the wildcard character and its preceding character are divided into an item to facilitate subsequent matching
-
Generate a two-dimensional array Boolean dp = new Boolean [N][M] where N is the pList length and M is the length of string s to be matched.
-
The pList is traversed one by one to match the characters in S. Obviously, in the matching rule, the position of the character in S from which the current match starts should start from the position where the last match can be matched.
So if pList[I] matches s[j], let dp[I][j] =true; To record the match between the matching card at I and the character at j. Dp [I][j] = true; dp[I] = true; The site.
If pList[I +1] is a wildcard, dp[I +1][j]=true; if pList[I +1] is a wildcard, dp[I +1][j]=true; If match, dp[I][j+e] = true, otherwise stop trying.
Dp [I +1][j+1]=true if pList[I +1]= s[j+1], dp[I +1]=true
code
class Solution {
public boolean isMatch(String s, String p) {
List<String> pList = getList(p);
int N = pList.size();
int M = s.length();
boolean[][] dp = new boolean[N][M];
int lastStart = -1;
int lastEnd = -1;
int j = 0,e=0;
boolean iMatch = false;
for(int i = 0; i<N; i++) { String cstr = pList.get(i);boolean isStar = isStar(cstr);
iMatch = false;
j = lastStart;
int tempLastEnd = lastEnd;
while(j<= tempLastEnd && j < M) {
if(j >= 0 && i-1> =0 && !dp[i-1][j] ) {++j;continue; }else if( j>=0 && i -1 <0) {++j;continue; }if (isStar) {/ / lastStart remains the same
iMatch = true;
if(j>=0) {
dp[i][j] = true;
lastEnd = j;
}
e = j+1;
while( e<M && match(cstr, s.charAt(e)) ) {
dp[i][e] = true; lastEnd = e; e++; }}else if(j < M-1 && match(cstr, s.charAt(j+1))) {if(! iMatch) { lastStart = j +1;
}
iMatch = true;
dp[i][j+1] = true;
lastEnd = j+1;
}
++j;
}
if(! iMatch)return false;
}
return dp[N-1][M-1];
}
private boolean match(String cstr,char c) {
return cstr.charAt(0) = ='. ' || cstr.charAt(0) == c;
}
private boolean isStar(String s) {
return s.contains("*");
}
private List<String> getList(String p) {
List<String> spList = new ArrayList<String>();
String s = "";
char c;
for(int i =0; i<p.length(); i++) { c = p.charAt(i);if (c == The '*') {
spList.add(s+"*");
s = "";
} else {
if(! s.isEmpty()) spList.add(s); s = c+""; }}if(! s.isEmpty()) spList.add(s);returnspList; }}Copy the code
Improve your code
In fact, the dp array above is actually a waste of space, because the slot at I, you only need to know the position in S where the last slot was matched. Modify the code as follows:
public boolean isMatch(String s, String p) {
List<String> pList = getList(p);
char[] sArray = s.toCharArray();
int N = pList.size();
int M = s.length();
boolean[][] dp = new boolean[2][M];
int lastStart = -1;// The point where the last point started true
int lastEnd = -1;
int j ,e;
int t;
boolean iMatch;
int tempLastEnd;
for(int i = 0; i<N; i++) { String cstr = pList.get(i);boolean isStar = isStar(cstr);
iMatch = false;
tempLastEnd = lastEnd;
if (i>0) {
t = (i-1) %2;
} else {
t = -1;
}
j = lastStart;
clear(dp,i%2,M);
while(j<= tempLastEnd && j < M) {
if(j >= 0 && t >=0 && !dp[t][j] ) {++j;continue; }else if( j>=0 && t <0) {++j;continue; }if (isStar) {/ / lastStart remains the same
iMatch = true;
if(j>=0) {
dp[i%2][j] = true;
lastEnd = j;
}
e = j+1;
while( e<M && match(cstr, sArray[e]) ) {
dp[i%2][e] = true; lastEnd = e; e++; }}else if(j < M-1 && match(cstr, sArray[j+1]) {if(! iMatch) { lastStart = j +1;
}
iMatch = true;
dp[i%2][j+1] = true;
lastEnd = j+1;
}
++j;
}
if(! iMatch)return false;
}
return dp[(N-1) %2][M-1];
}
Copy the code