public class Solution { public boolean match(char[] str, char[] pattern) { // 记忆化搜索 cache = new int[str.length + 1][pattern.length + 1]; return check(str, 0, pattern, 0); } private int[][] cache; // 记忆化搜索存储匹配结果 private boolean check(char[] str, int x, char[] pattern, int y) { if (cache[x][y] != 0) return cache[x][y] == 1; if (pattern.length == y) { // 模式串用完 cache[x][y] = str.length == x ? 1 : -1; return str.length == x; } boolean allMatch; // 全部匹配 boolean firstMatch = x < str.length && (pattern[y] == '.' || str[x] == pattern[y]); // 首字符匹配 if (y + 1 < pattern.length && pattern[y + 1] == '*') { if (firstMatch) allMatch = check(str, x, pattern, y + 2) || check(str, x + 1, pattern, y); else allMatch = check(str, x, pattern, y + 2); } else { allMatch = firstMatch && check(str, x + 1, pattern, y + 1); } cache[x][y] = allMatch ? 1 : -1; return allMatch; } }
动态规划思想。
eg:"abc","ab*.c"。
本质上是利用动态规划思想从后往前遍历。
如:i=2,j=4时,"c"和"c",true;
i=1,j=3时,"b"和"."匹配,则其结果与i+1,j+1时相同(true)。
public boolean match(char[] str, char[] pattern) { // pattern违背规则 if (pattern.length != 0 && pattern[0] == '*') return false; int i = str.length - 1, j = pattern.length - 1; while (i >= 0 || j >= 0) { // 字符匹配和pattern为'.'的情况 if (i >= 0 && j >= 0 && (str[i] == pattern[j] || pattern[j] == '.')) { i--; j--; // pattern为'*'的情况 } else if (j - 1 >= 0 && pattern[j] == '*') { return matchHelper(str, i + 1, pattern, j + 1); } else { return false; } } return i == -1 && j == -1; } /** * 动态规划计算遇到".w"后的匹配情况 * * @param str 原字符集 * @param sIndex 从后往前起始位置 * @param pattern 匹配规则字符集 * @param pIndex 起始位置 * @return 是否匹配 */ private boolean matchHelper(char[] str, int sIndex, char[] pattern, int pIndex) { boolean[][] dp = new boolean[sIndex + 1][pIndex + 1]; // 从后往前,str='',pattern=''时的情况 dp[sIndex][pIndex] = true; //以下举例str:[abc]和pattern:[abc*] for (int i = sIndex; i >= 0; i--) { for (int j = pIndex - 1; j >= 0; j--) { // 下一位是'*' if (j < pIndex - 1 && pattern[j+1] == '*') { // 是否和当前str[i]匹配(eg:i=3即str:'',pattern读到:c*) // 匹配,eg: i=2,j=2,即: // "c"和"c*"匹配结果由"c"和"" || ""和"c*"决定。 // 也就是说,碰到*且前面char匹配时,要么跳过"c*"(即*代表0个c), // 要么str继续向后读1位(eg:abccc,abc*),意为*多代表了1个c。 if (i != sIndex && (str[i] == pattern[j] || pattern[j] == '.')) { dp[i][j] = dp[i+1][j] || dp[i][j+2]; } else //若不匹配,则只能跳过“c*",此时*代表0个c dp[i][j] = dp[i][j+2]; // 若str[i]与pattern[j]匹配,则结果由二者都向后一位后的结果而定 // eg: i=0,j=0 此时[abc]和[abc*], // 其结果等于i=1,j=1时的结果,即[bc]和[bc*] } else if (i != sIndex && (pattern[j] == str[i] || pattern[j] == '.')) { dp[i][j] = dp[i+1][j+1]; } } } return dp[0][0]; }
/** * 回溯递归进行匹配 * @param str * @param pattern * @return */ public boolean match(char[] str, char[] pattern){ int len_s = str.length, len_p = pattern.length; // 判断 str 是否为空的字符数组 if (len_s == 0) { while (len_p - 2 >= 0 && pattern[len_p - 1] == '*') { len_p -= 2; } if (len_p == 0) { return true; }else { return false; } } // 判断 pattern 字符数组是否为空 if (len_p == 0) { if (len_s == 0) { return true; }else { return false; } } // 开始进行 逻辑判断 if (len_p == 1 || len_p > 1 && pattern[1] != '*') { //if the next character in pattern is not '*' if (str[0] == pattern[0] || (len_s > 0 && pattern[0] == '.')) { return match(String.valueOf(str).substring(1).toCharArray(), String.valueOf(pattern).substring(1).toCharArray()); }else { return false; } }else { //if the next character is '*' if (str[0] == pattern[0] || (len_s > 0 && pattern[0] == '.')) { // return match(str, String.valueOf(pattern).substring(2).toCharArray()) || match(String.valueOf(str).substring(1).toCharArray(), pattern); }else { return match(str, String.valueOf(pattern).substring(2).toCharArray()); } } }
public class Solution { public boolean match(char[] str, char[] pattern) { int size=str.length; int p_size=pattern.length; int p1=0; int p2=0; if(p_size==2&&pattern[0]=='.'&&pattern[1]=='*') return true; while(p1<size&&p2<p_size) { //下一个字符为‘*’ if(p2+1<p_size&&pattern[p2+1]=='*') { if(str[p1]==pattern[p2]||pattern[p2]=='.') { //计算str该字符有多少个 int n1=p1+1; while(n1<size&&str[p1]==str[n1]) { n1++; } int count1=n1-p1; //计算pattern该字符有多少个 int n2=p2+2; while(n2<p_size&&pattern[n2]==pattern[p2]) { n2++; } int count2=n2-p2; //是否满足匹配条件 if(count2-2<=count1) { p1=n1; p2=n2; continue; } else return false; } else { p2=p2+2; continue; } } //下一个字符不为‘*’,直接比较 if(str[p1]==pattern[p2]||pattern[p2]=='.') { p1++; p2++; continue; } else return false; } if(p1==size && p2==p_size) return true; else { //pattern多出来‘*’或者多出来“x*” if(p1==size && pattern[p_size-1]=='*'&&p_size-p2<=2) return true; if(p1==size) { int n2=p_size-1; int n1=size-1; //aaa和aa*c*a if(n1>=0 && pattern[n2]==str[n1]) { n2--; n1--; while(n1>0&&n2>p2&&pattern[n2]==str[n1]) { n1--; n2--; } } //aa和aa*c* while(n1>=0 && n2-1>=p2 && pattern[n2]=='*') { if(pattern[n2-1]!=str[n1]) { n2=n2-2; } if(n2-1<p2) return true; if(pattern[n2-1]==str[n1]&&p2==n2-1) { return true; } } return false; } else return false; } } }
public class Solution { public boolean match(char[] str, char[] pattern) { return match(str, 0, pattern, 0); } //回溯法 private boolean match(char[] str, int i, char[] pattern, int j) { if (str.length <= i && pattern.length - j == 2 && pattern[j+1] == '*') { // a* 的情况 return true; } if (i >= str.length && j >= pattern.length) { return true; } if (i >= str.length || j >= pattern.length) { return false; } if (j+1 < pattern.length && pattern[j+1] == '*') { if (pattern[j] != str[i] && pattern[j] != '.') { //当前2个不相等, pattern跳到*号后一个 return match(str, i, pattern, j+2); } else { if(match(str, i+1, pattern, j)) { //str跳下一个和pattern比 return true; } else { return match(str, i, pattern, j+2); } } } else if (j+1 == pattern.length || (j+1 < pattern.length && pattern[j+1] != '*')) { //字符后面不为*的情况 if (pattern[j] == str[i] || pattern[j] == '.') { return match(str, i+1, pattern, j+1); //两指针后移动,再比较 } else { return false; } } return false; } }
public class Solution { public boolean match(char[] str, char[] pattern){ int m = str.length; int n = pattern.length; boolean[][] dp = new boolean[m + 1][n + 1]; dp[0][0] = true; for (int i = 1; i <= n; i++) { if (pattern[i - 1] == '*') dp[0][i] = dp[0][i - 2]; } for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (pattern[j - 1] == str[i - 1] || pattern[j - 1] == '.') { dp[i][j] = dp[i - 1][j - 1]; } else if (pattern[j - 1] == '*') { if (pattern[j - 2] == str[i - 1] || pattern[j - 2] == '.') { dp[i][j] = dp[i][j - 1] || dp[i][j - 2] || dp[i - 1][j]; } else dp[i][j] = dp[i][j - 2]; } } } return dp[m][n]; } }
public class Solution { public boolean matchstr(char[] A,int i,char[] B,int j){ //边界 判断 if(i==A.length && j==B.length){ return true; }else if(j==B.length) { return false; }// boolean next =(j+1<B.length && B[j+1]=='*');// 模式串下一个字符是'*' if(next){ if(i<A.length && (B[j]=='.' || A[i]==B[j])){ return matchstr(A, i, B, j+2) || matchstr(A,i+1,B,j); }else { return matchstr(A, i, B, j+2); } }else{ if(i<A.length && (B[j]=='.' || A[i]==B[j])){ return matchstr(A, i+1, B, j+1); }else { return false; } } } public boolean match(char[] str, char[] pattern) { return matchstr(str,0,pattern,0); } }
循环写法虽然代码量长,但是挺简单的,从后往前比较public class Solution{ public static boolean match1(char[] str, char[] pattern){ int len1 = str.length-1; int len2 = pattern.length-1; //如果str为空数组,则只在pattern为空或者len2==1&&pattern[1]=='*'时返回true if(len1==-1){ if(len2==-1){ return true; } if(len2==1&&pattern[1]=='*'){ return true; } return false; } //字符串和模式都不为空 while(len1>=0 && len2>=0){ if(pattern[len2]=='*'){ --len2; while(str[len1]==pattern[len2]||pattern[len2]=='.'){ --len1; if(len1<0){ return true; } } --len2; } if(str[len1]==pattern[len2]||pattern[len2]=='.'){ --len1; --len2; } else if(pattern[len2]=='*'){ continue; } else{ return false; } } if(len1==-1&&len2==-1){ return true; } return false; } }
//使用dfs private boolean matchDfs(char[] str,int i,char[] pattern,int j){ if(i==str.length&&j==pattern.length) return true;//刚好匹配 if(j==pattern.length) return i==str.length;//pattern已经用完了,这时看str是否用完了 if(i==str.length){//str用完了 if(j==pattern.length-1) return false;//如果pattern只剩一个字符了,那是不可能匹配上的 if(pattern[j+1]=='*') return matchDfs(str,i,pattern,j+2);//pattern的j+1个字符是'*',这是可以使'*'匹配低j个字符0次 }else{//str没用完 if(j==pattern.length-1){//如果pattern只剩当前一个字符了(潜台词是后面没有'*') if(pattern[j]=='.'||pattern[j]==str[i]) return matchDfs(str,i+1,pattern,j+1);//str的当前字符可以和pattern的当前字符匹配 else return false;//不能匹配那就返回false了 }else{//pattern后续还有字符,也就是说可能存在'*' (之前的边界判断都是为了在这里方便的判断'*'是否存在) if(pattern[j+1]=='*'){//pattern后面一个字符是'*' if(str[i]!=pattern[j]&&pattern[j]!='.') return matchDfs(str,i,pattern,j+2);//str的当前字符和pattern的当前字符不匹配,这时可以使'*'匹配0次 else return matchDfs(str,i,pattern,j+2)||matchDfs(str,i+1,pattern,j);//当前字符匹配,那么可以继续匹配0次或大于等于1次 }else{//后面一个字符不是'*' if(str[i]!=pattern[j]&&pattern[j]!='.') return false;//当前字符不匹配,返回false else return matchDfs(str,i+1,pattern,j+1);//当前字符匹配,那么继续匹配下一个 } } } return false; } public boolean match(char[] str, char[] pattern) { if(str==null&&pattern==null) return true; if(str==null||pattern==null) return false; if(pattern.length==0) return str.length==0; return matchDfs(str,0,pattern,0); }
//tip: 使用正则表达式 public boolean match(char[] str, char[] pattern) { Pattern p=Pattern.compile(String.valueOf(pattern)); Matcher m=p.matcher(String.valueOf(str)); if(m.find()){ if(m.group().equals(String.valueOf(str))) return true; } return false; }
public boolean match(char[] str, char[] pattern) { if (str.length == 0 && pattern.length == 0) { return true; } return matchCore(str, pattern, 0, 0); } public boolean matchCore(char[] str, char[] pattern, int strIndex, int patIndex) { if (strIndex == str.length && patIndex == pattern.length) { return true; } if (strIndex != str.length && patIndex == pattern.length) { return false; } // 下一个是* if (patIndex + 1 < pattern.length && pattern[patIndex + 1] == '*') { if (strIndex == str.length || str[strIndex] != pattern[patIndex] && pattern[patIndex] != '.') { return matchCore(str, pattern, strIndex, patIndex + 2); // 当前不匹配,只能跳过 } else { return matchCore(str, pattern, strIndex + 1, patIndex) || matchCore(str, pattern, strIndex, patIndex + 2); // 当前匹配,可选择是否跳过 } } // 下一个不是* if (strIndex < str.length && (str[strIndex] == pattern[patIndex] || pattern[patIndex] == '.')) { return matchCore(str, pattern, strIndex + 1, patIndex + 1); } else { return false; } }看了一遍书本答案后再写就简单多了,思路也比较清晰。。自己的改了半天难看得要死...
public boolean match(char[] str, int strIndex,char[] pattern,int patIndex)
(patIndex==patLen-1||pattern[patIndex+1]!='*')应该放一起。)当匹配串当前字符为 ".",可以匹配任意字符;或者两个字符相同时,结果为两个下标分别+1 去看匹配结果,否则,得返回 false。
public class Solution { //思路:递归求解 public boolean match(char[] str, char[] pattern) { if(str==null||pattern==null) return false; return match(str,0,pattern,0);} public boolean match(char[] str, int strIndex,char[] pattern,int patIndex) { int strLen=str.length; int patLen=pattern.length; //如果模式串遍历完,而str 也完,应当返回 true if(patIndex==patLen&&strIndex==strLen) { return true;} //如果模式串遍历完,而str 没完,应当返回 false if(patIndex==patLen&&strIndex!=strLen) {return false;} //接下来都是 模式串没完的情况 if(patIndex==patLen-1||pattern[patIndex+1]!='*') { if(strIndex==strLen) return false; if(pattern[patIndex]=='.'||pattern[patIndex]==str[strIndex]) return match(str,strIndex+1,pattern,patIndex+1); else return false; else { if(strIndex==strLen) return match(str,strIndex,pattern,patIndex+2); if(pattern[patIndex]=='.'||str[strIndex]==pattern[patIndex]) return match(str, strIndex + 1, pattern, patIndex + 2) || match(str, strIndex , pattern, patIndex + 2) || match(str, strIndex + 1, pattern, patIndex); else return match(str,strIndex,pattern,patIndex+2); }}}
* 思路:找出重点关注的地方分情况讨论 * ∵ .表示任意字符,所以当模式中的某个字符为.或和字符串中的某字符相等时则匹配,进入下一个字符比较 * 重点考虑* * 一般情况: * 当第二个字符为*时(第一个字符为*没有意义,划分问题规模),可以选择三种情况 * * 如果str第一个字符与pattern第一个字符相同或者pattern第一个字符为.,此时*和前面的字符匹配 * 第一种:模式向后移动2个字符,字符串向后移动1个字符,继续匹配(比如aaa和a*a*a) * 第二种: 模式不移动,字符串向后移动一位,继续匹配* (比如aaa和a*) * 第三种:模式向后移动2个字符,*表示前面字符为0,相当于忽略*和前面的字符,字符串不移动(比如aaa和a*a*a*a) * * 如果str第一个字符与pattern第一个字符不相同,此时*和前面的字符不匹配 * 模式向后移动两位,字符串向后移动一位,比较下一位,(比如aaa和b*a*b) * * ======================== * 如果第二个字符不为* * 当第一个字符一样,可能匹配成功或者失败,进入递归 * 如果第一个字符不一样,则必定失败(为*可以表示前一个字符出现0次) *======================== * 找出base case(何时才算匹配成功): * 当str和pattern都走到尾,表示pattern匹配str成功 * 当str未走到尾,pattern已经走到尾,此时pattern匹配str失败,str还有剩余字符未匹配 * 当str走到尾,pattern未走到尾,或str和pattern都未走到尾,此时可能匹配成功,也可能失败,进入一般情况。 * */ public class Solution { public boolean match(char[] str, char[] pattern) { if (str == null || pattern == null) { return false; } return matchCore(0, str, 0, pattern); } private boolean matchCore(int strIndex, char[] str, int patternIndex, char[] pattern) { if (strIndex == str.length && patternIndex == pattern.length) { return true; } if (strIndex != str.length && patternIndex == pattern.length) { return false; } // 注意保证数组下标不越界 // 第二个字符为* if ((patternIndex + 1) < pattern.length && pattern[patternIndex + 1] == '*') { if ((strIndex < str.length && str[strIndex] == pattern[patternIndex]) || (strIndex < str.length && pattern[patternIndex] == '.')) { return matchCore(strIndex, str, patternIndex + 2, pattern) || matchCore(strIndex + 1, str, patternIndex + 2, pattern) || matchCore(strIndex + 1, str, patternIndex, pattern); } else { // 第一个字符不匹配 return matchCore(strIndex, str, patternIndex + 2, pattern); } } if ((strIndex < str.length && pattern[patternIndex] == str[strIndex]) || (strIndex < str.length && pattern[patternIndex] == '.')) { // 第二个字符不为*,第一个字符匹配 return matchCore(strIndex + 1, str, patternIndex + 1, pattern); } return false; } }
public class MatchPattern { public boolean match(char[] str, char[] pattern) { if(str == null || pattern == null) return false; return matchCore(str,0,pattern,0); } private boolean matchCore(char[] str,int strIndex,char[] pattern ,int patternIndex){ if(strIndex == str.length && patternIndex == pattern.length) return true; if(strIndex < str.length && patternIndex == pattern.length) return false; if(patternIndex + 1< pattern.length && pattern[patternIndex + 1] == '*'){ if((strIndex < str.length && pattern[patternIndex] == '.') ||(strIndex < str.length && pattern[patternIndex] == str[strIndex])){ return matchCore(str,strIndex,pattern,patternIndex + 2) ||matchCore(str,strIndex+1,pattern,patternIndex + 2) ||matchCore(str,strIndex+1,pattern,patternIndex); } else{ return matchCore(str,strIndex,pattern,patternIndex + 2); } } if((strIndex < str.length && patternIndex < pattern.length && str[strIndex] == pattern[patternIndex]) || (strIndex < str.length && patternIndex < pattern.length && pattern[patternIndex]== '.')){ return matchCore(str,strIndex + 1,pattern,patternIndex + 1); } return false; } }
//动态规划解法 public class Solution { public boolean match(char[] str, char[] pattern) { boolean[][] dp; int i, j, ls, lp; ls = str.length; lp = pattern.length; dp = new boolean[lp+1][ls+1]; dp[0][0] = true; for(i = 0; i < lp; i++) if(pattern[i] == '*') dp[i+1][0] = dp[i-1][0]; for(i = 0; i < lp; i++){ for(j = 0; j < ls; j++){ if(pattern[i] == '*') dp[i+1][j+1] = dp[i-1][j+1] || dp[i][j+1] || (str[j] == pattern[i-1] || pattern[i-1] == '.') && dp[i+1][j]; else if(pattern[i] == '.' || pattern[i] == str[j]) dp[i+1][j+1] = dp[i][j]; else dp[i+1][j+1] = false; } } return dp[lp][ls]; } }
public class Solution { public boolean match(char[] str, char[] pattern){ if(str == null || pattern == null) return false; if(str.length == 0){ if(pattern.length == 0 || (pattern.length == 2 && pattern[1] == '*')){ return true; }else{ return false; } } if(pattern.length == 0)return false; int i = 0; int j = 0; while(i < str.length){ if(j == pattern.length - 1){ if(i == str.length - 1 && (str[i] == pattern[j] || pattern[j] == '.')){ return true; }else{ return false; } } if(j > pattern.length - 1) return false; if(pattern[j + 1] == '*'){ int index = i; // 记录回退数量,管理这样的"a*a"的匹配 int back = 0; int point = j + 1; while(++point <= pattern.length - 1 && ((index + 1 < str.length && str[index + 1] == pattern[j]) || index + 1 == str.length)){ if(pattern[point] == pattern[j]){ back++; if(point + 1 <= pattern.length - 1 && pattern[point] == '*')back--; } } // 单独处理"."的回退问题 while(++point <= pattern.length - 1 && pattern[j] == '.'){ back++; if(point + 1 <= pattern.length - 1 && pattern[point] == '*')back--; } while(index < str.length && (str[index] == pattern[j] || pattern[j] == '.')){ index++; } index-=back; if(index == str.length && j + 1 == pattern.length - 1)return true; if(j + 1 == pattern.length - 1)return false; if(index == str.length)return false; j+=2; i = index; }else{ if(str[i] != pattern[j] && pattern[j] != '.')return false; i++; j++; } } if(j + 1 == pattern.length - 1 && pattern[j + 1] == '*')return true; return false; } }
public class Solution { public boolean match(char[] str, char[] pattern) { String string = new String(str); String regex = new String(pattern); return string.matches(regex); } }