LeetCode 10.正規表現マッチング正規の試合
10.正規表現のマッチング
入力文字列(所与s
)及びパターン(p
)をサポートする正規表現マッチング実装'.'
とを'*'
。
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
マッチングは、カバーすべき全入力文字列(部分的ではないが)。
注意:
s
空と小文字のみが含まれてできましたa-z
。p
空であると小文字のみが含ま可能性がありa-z
、などの文字.
またはを*
。
例1:
Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
例2:
Input:
s = "aa"
p = "a*"
Output: true
Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
例3:
Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".
例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".
例5:
Input:
s = "mississippi"
p = "mis*is*p*."
Output: false
リカーシブ
それは繰り返し動作の多くを必要とするため、再帰の最大の欠点は、非効率的です。
私たちは、文字を一つずつを一致させることができます。「*」が懸念しているため簡単には、文字列マッチングに対応し、後続の文字列の必要性を見つけるために。「」懸念しているために、それは任意の文字に対応し、すべての文字が一致するが、その成功に一致するように考えられています。
public boolean isMatch(String s, String p) {
if(p.isEmpty()){
return s.isEmpty();
}
boolean first_match = (!s.isEmpty() && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.'));
if(p.length() >= 2 && p.charAt(1) == '*'){
return (isMatch(s,p.substring(2)) || (first_match && isMatch(s.substring(1),p)));
} else {
return first_match && isMatch(s.substring(1),p.substring(1));
}
}
ダイナミックプログラミング
私たちは、重複計算を避けるために、計算されたレコードの配列の結果の結果を使用することができます。これは、動的プログラミングを使用してのアイデアです。
トップダウン
class Solution {
Boolean[][] result;
public boolean isMatch(String s, String p) {
result = new Boolean[s.length() + 1][p.length() + 1 ];
// return result[0][0];
return dp(0,0,s,p);
}
public boolean dp(int sIndex, int pIndex,String s, String p){
if(result[sIndex][pIndex] != null){
return result[sIndex][pIndex] == true;
}
boolean ans;
int sLen = s.length();
int pLen = p.length();
if(pIndex == pLen){
ans = sIndex == sLen;
} else {
boolean first_match = (sIndex < sLen) && (p.charAt(pIndex) == s.charAt(sIndex) || p.charAt(pIndex) == '.');
if(pIndex + 1 < pLen && p.charAt(pIndex + 1) == '*'){
ans = dp(sIndex,pIndex+2,s,p) || first_match && dp(sIndex+1,pIndex,s,p);
} else {
ans = first_match && dp(sIndex+1,pIndex+1,s,p);
}
}
result[sIndex][pIndex] = ans?true:false;
return ans;
}
}
自底向上
public boolean isMatch(String text, String pattern) {
boolean[][] dp = new boolean[text.length() + 1][pattern.length() + 1];
dp[text.length()][pattern.length()] = true;
for (int i = text.length(); i >= 0; i--){
for (int j = pattern.length() - 1; j >= 0; j--){
boolean first_match = (i < text.length() &&
(pattern.charAt(j) == text.charAt(i) ||
pattern.charAt(j) == '.'));
if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){
dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];
} else {
dp[i][j] = first_match && dp[i+1][j+1];
}
}
}
return dp[0][0];
}
}
NFA(非自動有限ベクター)
あなたは、処理のために、有限非自動ベクトルマシンのコンパイラの理論を使用することができます。言語の種類として正規表現。次に、入力状態の遷移に応じ。単純な用語である:*の入力値を受信した場合、初期状態Aと仮定する、状態Bに入ります 通常の試合の原理は次のリンクを参照することができます
原理ます。https://swtch.com/~rsc/regexp/regexp1.html
class Solution {
private static final char ONE= '.';
private static final char MANY= '*';
private static final char SPLIT= '<';
private static final char END= '$';
public boolean isMatch(String s, String p) {
if (p.isEmpty()) return s.isEmpty();
return nfa(s, p);
}
static class State {
public int id;
public char c; // state char
public State out1; // next state 1
public State out2; // next state 2 (for split state only)
public State(int id, char c){
this.id= id;
this.c= c;
}
@Override
public int hashCode(){
return id*c;
}
@Override
public boolean equals(Object o){
return id==((State)o).id && c==((State)o).c;
}
}
private boolean nfa(String s, String p){
State match= new State(p.length(), END);
Set<State> clist= new HashSet<>(); // current list of states
Set<State> nlist= new HashSet<>(); // next list of states
State start= buildNfa(p, match);
addState(clist, start);
for(int i=0; i<s.length() && !clist.isEmpty(); i++){
step(clist, s.charAt(i), nlist);
Set<State> temp= clist;
clist= nlist;
nlist= temp;
nlist.clear();
}
return hasMatch(clist, match);
}
private void step(Set<State> clist, char c, Set<State> nlist){
for(State state:clist)
if (state.c==ONE && state.out1!=null)
addState(nlist, state.out1);
else if (c==state.c && state.out1!=null)
addState(nlist, state.out1);
}
private void addState(Set<State> list, State state){
if (state.c==SPLIT){
addState(list, state.out1);
addState(list, state.out2);
return;
}
list.add(state);
}
private boolean hasMatch(Set<State> list, State match){
return list.contains(match);
}
private State buildNfa(String p, State match){
int n= p.length();
State start= null;
State prev_state= null, state= null, split= null;
for(int i=0; i<p.length(); i++){
char c= p.charAt(i);
char next_c= i<n-1 ? p.charAt(i+1) : END;
if (next_c==MANY){
split= new State(i+1, SPLIT); // split state character
state= new State(i, c);
split.out2= state;
state.out1= split;
if (prev_state!=null) prev_state.out1= split;
if (start==null) start= split;
prev_state= split;
i++; // consume 2 characters
}else{
state= new State(i, p.charAt(i));
if (prev_state!=null) prev_state.out1= state;
if (start==null) start= state;
prev_state= state;
}
}
prev_state.out1= match;
return start;
}
}