Implement wildcard pattern matching with support for ‘?’ and ‘*’.
Java Solution
To understand this solution, you can use s=”aab” and p=”*ab”.
public boolean isMatch(String s, String p) { int i = 0; int j = 0; int starIndex = -1; int iIndex = -1; while (i < s.length()) { if (j < p.length() && (p.charAt(j) == '?' || p.charAt(j) == s.charAt(i))) { ++i; ++j; } else if (j < p.length() && p.charAt(j) == '*') { starIndex = j; iIndex = i; j++; } else if (starIndex != -1) { j = starIndex + 1; i = iIndex+1; iIndex++; } else { return false; } } while (j < p.length() && p.charAt(j) == '*') { ++j; } return j == p.length(); } |
what is iIndex here?
public static boolean isMatch(String a, String b){
if(a == null || b == null){
return false;
}
if(a.length() != b.length()){
return false;
}
for( int i=0 ; i < a.length() ; i++){
char c1 = a.charAt(i);
char c2 = b.charAt(i);
if( c2 != '*' && c2 != '?'){
if(c1 != c2){
return false;
}
}
}
return true;
}
There are too many cases where this might fail, though it works fine for the example taken above.
like if s=a and p=*aab, this will fail
That solution takes O(mn) space. This one takes O(1) space.
https://github.com/mission-peace/interview/blob/master/src/com/interview/dynamic/WildCardMatching.java
easier and better solutions here.
very Simple understanding solution replace “.” with “?”
/* package whatever; // don’t place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be “Main” only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
//System.out.println(isMatchMain(“.”,”a”));
System.out.println(isMatchMain(“abc*bcd”, “abcdhghgbcd”));
}
public static boolean isMatchMain(String P, String S) {
if(P == null || S == null || P.length() == 0 || S.length() == 0) return false;
return isMatch( P, S);
}
public static boolean isMatch(String P, String S) {
if(P.length() == 0 && S.length() == 0) {
return true;
}
if(S.length() == 0 && !P.equals(“*”)) return false;
if(isCharEqual(‘.’, P) || equalsString(P, S)) {
return isMatch(P.substring(1), S.substring(1));
}
if(isCharEqual(‘*’, P)) {
return isMatch(P.substring(1), S) || isMatch(P, S.substring(1));
}
return false;
}
public static boolean isCharEqual(char ch, String S) {
if(S.length() > 0 && ch == S.charAt(0)) return true;
return false;
}
public static boolean equalsString(String P, String S) {
if(P.length() > 0 && S.length() > 0 && S.charAt(0) == P.charAt(0)) return true;
return false;
}
}
I believe it is Processing O(N^2) (N square) and Space O(1).
Is N^2 in the following pathological case:
String s = “aaaaaaaaab”;
String p = “*aaaaaaaaz”;
I think a clarification is in order here, in some regex patterns the meaning of the special chars is:
?: zero or one occurrence of the _previous_ char
*: zero or more occurrence of the _previous_ char.
Also you should say which greediness logic is used (for ‘*’). Normally * is greedy, that is, it “consumes” as much from the input string as possible.
Here is my solution for the above specified logic (which I understand is not the same used in the example solution):
Note: this assumes the existence of a special “non-valid” char (used ”) which may not be a valid assumption. Can be adapted to avoid this (e.g. using null and Character). Also, provides some validations for the pattern expression.
boolean isMatch(String str, String pattern) {
if (str.isEmpty() ^ pattern.isEmpty()) return false;
int matchingSpecialRemaining = 0;
char matchingChar = '';
int i = 0;
int p = 0;
while (i p && matchingSpecialRemaining == 0) {
matchingChar = pattern.charAt(p);
//may add check for special char for sanity (invalid expression)
++p;
if (pattern.length() > p) { //look ahead for a special char
switch (pattern.charAt(p)) {
case '?':
matchingSpecialRemaining = 1;
++p;
break;
case '*':
matchingSpecialRemaining = -1;
++p;
break;
}
}
} else if (matchingSpecialRemaining == 0) {
matchingChar = ''; //or some other invalid char
}
if (str.charAt(i) == matchingChar) {
if (matchingSpecialRemaining == 1) matchingSpecialRemaining = 0;
++i;
} else {
if (matchingSpecialRemaining == 0) return false;
else matchingSpecialRemaining = 0;
}
}
//we completed the str, need to check if there is still pattern to match
while (p < pattern.length()) {
int next = p + 1;
//if there is a char but no wildcard, pattern not matched
if ((pattern.length() <= next) || (pattern.charAt(next) != '*' && pattern.charAt(next) != '?') )
return false;
p = next + 1;
}
return true;
}
Notice there’s no if (p == s) return p; at the first line, I mean don’t you want to see if they’re equal?
This fails because the test
p.charAt(j) == s.charAt(i)
can cause a * in p to be regarded as a normal character if there is also a * in s.public static boolean isMatch(String s, String p) {
if (s.isEmpty() && p.isEmpty()) return true;
if (p.isEmpty()) return false;
if (s.isEmpty()) {
return isAllStar(p);
}
char sC = s.charAt(0);
char pC = p.charAt(0);
if (pC == '*') {
boolean res = isMatch(s, p.substring(1));
if (!res) {
res = isMatch(s.substring(1), p);
}
return res;
} else if (pC == '?' || sC == pC) {
return isMatch(s.substring(1), p.substring(1));
}
return false;
}
private static boolean isAllStar(final String p) {
for (char c : p.toCharArray()) {
if (c != '*') return false;
}
return true;
}
this will fail for input “aaaabbbbcccc” “a*”
string s = "acab";
string p = "?*b";
size_t i = 0, j = 0;
bool wildcard = true;
while (i < s.length()) {
if (s[i] == p[j] || p[j] == '?') {
i++;
j++;
} else if (p[j] == '*') {
size_t found = s.find_first_of(p[j+1], i);
if (found != string::npos) {
j = j + 2;
i = found + 1;
continue;
} else {
wildcard = false;
break;
}
} else {
wildcard = false;
break;
}
}
cout << "Is wild card: " << wildcard << "n";
You should also post some detailing like Time and Space Complexity of the solution.. although its fine..