Facebook Interview Question for Software Engineer Interns


Country: United States
Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
2
of 2 vote

public static boolean match(char text[], char pattern[]) {
		if (text == null || text.length == 0) return false;
		if (pattern == null || pattern.length == 0) return false;
		
		for (int i=0, j=0; i<text.length; i++) {
			if (pattern[j] == '.') {
				j++;
			}
			else if (j > 0 && pattern[j] == '*') {
				if (text[i] != pattern[j-1]) {
					if (text[i] == pattern[j+1]) {
						j++;
					}
					else {
						return false;
					}
				}
			}
			else {
				if (text[i] != pattern[j]) {
					return false;
				}
				else {
					j++;
				}
			}
		}
		
		
		return true;
	}

- Kevin February 16, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Cannot pass many test cases, such as "aa", "a" or "aa", ".*"

- hlfshiren September 06, 2014 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

Here is my working code in Java:

public class StringMatchWithWildCards {

    public static boolean matchStrings(String text, String pattern) {

        int lengthText = text.length();
        int lengthPattern = pattern.length();
        int i = 0;
        int j = 0;

        while(i < lengthText) {
            if(j == lengthPattern)  // pattern can never be longer
                return false;       // than the original text

            if(text.charAt(i) == pattern.charAt(j) || pattern.charAt(j) == '.') {
                j = j + 1;
            }
            else if (pattern.charAt(j) == '*') {
                // here, we need to count instances
                // in text, that correspond to this
                // character.
                char currTextChar = text.charAt(i);
                char prevPatternChar = pattern.charAt(j-1);
                if(currTextChar != prevPatternChar) {   // this means the '*'
                                                        // denotes no character
                    i = i - 1;  // restore i to current position
                    j = j + 1;  // after it's re-increment by 1
                }
                else {
                    // fast forward i to point to character
                    // where (currTextChar != prevPatternChar)
                    while(i < lengthText && currTextChar == prevPatternChar) {
                        currTextChar = text.charAt(i);
                        i = i + 1;
                    }

                    if(i == lengthText) {// text reached end first
                        return (j == lengthPattern - 1);
                    }
                    else {
                        i = i - 1; // same as above. ready for
                        j = j + 1; // next piece of string matching
                    }
                }
            }
            else return false;

            i = i + 1;
        }


        return (i == lengthText && j == lengthPattern);
    }
}

Also, here is the test class:

public class StringMatchWithWildCardsTest {

    @Test
    public void testMatchStrings() {
        Assert.assertFalse(StringMatchWithWildCards.matchStrings("Facebook", "F*cebo.k"));
        Assert.assertTrue(StringMatchWithWildCards.matchStrings("Facebook", "F.cebo.k"));
        Assert.assertTrue(StringMatchWithWildCards.matchStrings("Facebooo", "Facebo*"));
        Assert.assertFalse(StringMatchWithWildCards.matchStrings("Facebooker", "F.cebo*"));
    }
}

- Killedsteel February 13, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Btw, ignore the following comment in the code. It was just something I was thinking of.

// pattern can never be longer
// than the original text

Explanation: The code basically checks each of the edge cases iteratively. The '*' character could be at the end, or at the second position. Consecutively, pattern.length may be greater than text.length, or vice versa.

Note: I forgot to implement the edge-case where the '*' character is the first character in the pattern string. In this case, it probably makes sense to throw an IllegalArgumentException exception. Maybe I can leave this as an exercise for someone to implement :)

- Killedsteel February 13, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I think this code will fail for the following case:

Pattern: Facebo*ok
String: Facebook

- Anonymous February 15, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I just tested it. It seemed to work.

Assert.assertFalse(StringMatchWithWildCards.matchStrings("Facebook", "Facebo*ok"));

If you meant it to be the other way, I tried that too. And that worked as well.

Assert.assertFalse(StringMatchWithWildCards.matchStrings("Facebo*ok", "Facebook"));

- Killedsteel February 15, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@Killedsteel

StringMatchWithWildCards.matchStrings("Facebook", "Facebo*ok")

should return true not false.

- Julien February 15, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@Julien: Oh, you're right! I came up with a quick fix for this. Change the following:

char currTextChar = text.charAt(i);
                char prevPatternChar = pattern.charAt(j-1);

to this:

if(text.substring(i, text.length()).equals(pattern.substring(j+1, pattern.length())))
                    return matchStrings(text.substring(i), pattern.substring(j+1)); // '*' may represent
                                                                                  // no characters at all
                char currTextChar = text.charAt(i);
                char prevPatternChar = pattern.charAt(j-1);

Note: This is a temporary fix, only to address the above issue. But in general, I understand what the problem here is. We need to measure the number of similar characters in the text, say A, then measure the number of characters in the pattern, that are similar to the character before the '*', say B. We then need to calculate A-B. Those are the number of characters in text that the start represents. We then change

i = i - 1; // same as above. ready for
                        j = j + 1; // next piece of string matching

to

i = i - B;        // same as above. ready for
                        j = j + A - B; // next piece of string matching

- Killedsteel February 15, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

EDIT: ...number of characters in text that the star* represents.

Perhaps another modification exercise for someone? :)

- Killedsteel February 15, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

I just tested with case: matchStrings("faceboooook", "f.ceb..o*k")
should print true, but it prints false

- guilhebl February 18, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

It will fail this case: facebook / face.*k

- Yaohuah February 19, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Here is a basic recursive solution. Few check like the first string should only have alphabets and digits can also be added

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class StringMatch {
	public static void main(String[] args) throws IOException {
		BufferedReader obj = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("Enter the main String");
		String input1 = obj.readLine();
		System.out.println("Enter the second String ");
		String input2 = obj.readLine();
		boolean matchSuccessful=match(input1,input2,input1.length(),input2.length());
	    System.out.println(matchSuccessful);
	}

	private static boolean match(String input1, String input2, int i, int j) {
		if(i==0 && j==0)
		return true;
		else{
			if(input1.charAt(0)==input2.charAt(0)||input2.charAt(0)=='.')
				return match(input1.substring(1),input2.substring(1),i-1,j-1);
			else if(input2.charAt(0)=='*'){
				return match(input1.substring(1),input2.substring(1),i-1,j-1)||match(input1.substring(1),input2,i-1,j);
			}
		}
		return false;
	}

}

- martin1990 February 13, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Wouldn't this fail for the following test case?
Text: Facebook
Pattern: Fac*book

What the ' * ' represents is _not_ a simple replacement for multiple characters, but a replacement for repetition of zero or more instances of the _previous_ character.

- Killedsteel February 13, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

It should fail for
Text: Facebook
Pattern: Fac*book

What * represents here is after 'c'. It can control 0 or more instances of 'c' but cannot replace 'e' in that string.

- Zero2 February 16, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Adding one more argument to the match method will work , I guess

private static boolean match(String input1, String input2, int i, int j,char previousChar) {
		if(i==0 && j==0)
		return true;
		else{
			if(input1.charAt(0)==input2.charAt(0)||input2.charAt(0)=='.')
				return match(input1.substring(1),input2.substring(1),i-1,j-1,input2.charAt(0));
			else if(previousChar==input1.charAt(0) && input2.charAt(0)=='*'){
				return match(input1.substring(1),input2.substring(1),i-1,j-1,input2.charAt(0))||match(input1.substring(1),input2,i-1,j,previousChar);
			}
		}
		return false;
	}

- martin1990 February 16, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static boolean compaire(String st, String pattern) {
        boolean result = false;
        if (st.length() == pattern.length()) {
            char a1[] = st.toCharArray();
            char a2[] = pattern.toCharArray();
            for (int i = 0; i < a1.length; i++) {
                System.out.println(" First "+a1[i]+" Second "+a2[i] );
                if (a1[i] == a2[i]) {
                    result = true;
                } else {
                    if (a2[i] == '.') {
                        if ((a1[i] >= 'a' && a1[i] <= 'z') || (a1[i] >= 'A' && a1[i] <= 'Z') || (a1[i] >= '0' && a1[i] <= '9')) {
                            result = true;
                        } else {
                            return false;
                        }
                    } else if (a2[i] == '*') {
                        
                        if (i > 0 && (a2[(i-1)] == a1[i])) {
                            result = true;
                        } else {
                            return false;
                        }
                    } else {
                        return false;
                    }
                }
            }
        } else {
            return false;
        }
        return result;
    }

- Mohammad Husain February 13, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

This code is incorrect - the two string can have different lengths and you didn't account for that especially in this statement -

if (i > 0 && (a2[(i-1)] == a1[i]))

- bobby February 13, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

public class MatchExp {
    static boolean match(String input, String match){
        return matchExp(input.toLowerCase(),match.toLowerCase(),0,0);
    }

    static boolean  matchExp(String input, String match, int i, int j){


        if(i==input.length() && j==match.length()) return true;
        if(i==input.length()) return false;
        if(j==match.length()) return false;

        if(match.charAt(j)=='*'){
            boolean matchVal = false;
            for(int k  = i;k<input.length();k++){
                matchVal |= matchExp(input,match,k,j+1);
            }
            return matchVal;
        }

        return (match.charAt(j) == input.charAt(i) || match.charAt(j) == '.') && matchExp(input, match, i + 1, j + 1);

    }

    public static void main(String arvg[]){
       Boolean ans =  match("facebook123","F.cebo*k12*3");
       System.out.print(ans);
    }
}

- Anonymous February 13, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

If you input "facebk", "facebo*k", the output is false.
However, they are matched, as * represent 0 or more times.

- Anonymous February 14, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static boolean doesPatternMatch(String text, String patt)
{
//dp[i][j] = true if first "i" characters of pattern matches with first "j" characters of text
boolean[][] dp = new boolean[patt.length()][text.length()];


//base case
if(patt.charAt(0)=='.' || patt.charAt(0) == text.charAt(0))
{
dp[0][0]=true;
}else{
dp[0][0]=false;
}

for(int k=1;k<text.length();k++)
{
if(patt.charAt(0) == '*')
dp[0][k]=true;
else
dp[0][k]=false;
}

for(int k=1;k<patt.length();k++)
{
if(patt.charAt(k) == '*')
{
dp[k][0] = dp[k-1][0];
}else
{
dp[k][0]=false;
}
}


for(int i=1;i<patt.length();i++)
{
for(int j=1;j<text.length();j++)
{
if(patt.charAt(i) == '*')
{
dp[i][j] = dp[i-1][j-1] || dp[i-1][j];
}else if(patt.charAt(i) == '.')
{
dp[i][j] = dp[i-1][j-1];
}else if(patt.charAt(i) == text.charAt(j))
{
dp[i][j] = true;
}else{
dp[i][j] = false;
}
}
}

return dp[patt.length()-1][text.length()-1];
}

- Anonymous February 14, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Here is the C code:

bool is_match(char * str1,char * str2)
{
    //str2 has wildcard characters
    //1. '.' means match single character
    //2. '*' means previous character repeat 0 or # of times
    //base case
    if(*str1 == '\0')
    {
        if(*str2 != '\0' && *str2 != '*')
        return false;   //doesn't match
        while(*str2 == '*')
        str2++;
        if(*str2 == '\0')
        return true;
        else
        return false;
    }
    if(*str1 && !(*str2))
    return false;
    
    if(*str2 == '.')    //1 character match
    return is_match(str1+1,str2+1);
    else if(*str2 == '*')
return ((is_match(str1,str2+1)) || (*str1 == *(str1+1)?is_match(str1+1,str2):is_match(str1+1,str2+1)));
   else 
   {
       if(*str1 == *str2)
       return is_match(str1+1,str2+1);
       else
       return false;
   }
}

- Sumit Monga February 15, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

def match2(s1, s2, prev=None):
    if not len(s1):
        return True
    elif s1[0] == s2[0]:
        return match2(s1[1:], s2[1:], s2[0])
    elif s2[0] == "." and (str.isdigit(s1[0]) or str.isalpha(s1[0])):
        return match2(s1[1:], s2[1:], s2[0])
    elif s2[0] == "*" and s1[0] == prev:
        return match2(s1[1:], s2, prev)
    elif s2[0] == "*" and s1[0] != prev:
        return match2(s1, s2[1:], s2[0])
    return False

- dgomes February 15, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

I have question I saw comment that the code should return true for StringMatchWithWildCards.matchStrings("Facebook", "Facebo*ok") but isn't pattern equivalent to Faceboook and it should rather fail?

- anony February 17, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

boolean isAMatch(int s_idx, int p_idx) {

if(s_idx == str.length() && p_idx == pat.length()) {
return true;
}

if(s_idx == str.length() || p_idx == pat.length()) {
return false;
}

if(str.charAt(s_idx) == pat.charAt(p_idx)) {
return isAMatch(s_idx+1, p_idx+1);
}

else if(pat.charAt(p_idx) == '.') {
return isAMatch(s_idx+1, p_idx+1);
}
else if(pat.charAt(p_idx) == '*') {

boolean case_A = false;
boolean case_C = false;
if(s_idx+1 < str.length() && str.charAt(s_idx+1) == str.charAt(s_idx)) {
case_A = isAMatch(s_idx+1, p_idx);
}
//0 characters
boolean case_B = isAMatch(s_idx, p_idx+1);
//both match
if(p_idx > 0 && str.charAt(s_idx) == pat.charAt(p_idx-1)) {
case_C = isAMatch(s_idx+1, p_idx+1);
}
return ( case_A || case_B ||case_C);
}
return false;
}

- Neha February 19, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

bool ismatch(const char* s, const char* p)
{
	if(!s || !p) return false;
	if(*p == '\0') return *s == '\0';
	if(*(p+1) == '*'){
		if(*s == *p || (*p == '.' && *s != '\0')) return ismatch(s+1, p) || ismatch(s, p+2);
		return ismatch(s, p+2);
	}
	else{
		if(*s == *p || (*p == '.' && *s != '\0')) return ismatch(s+1, p+1);
		return false;
	}
}

- Anonymous February 23, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Ok , it was telephonic . I will explain logic
Assuming there can be more than one occurrence of *
Taking example /temp/*my*jpeg

Calculate firstst occurrence of *
Calculate lastst occurrence of *
So know you know the prefix ans sufix string which need to be matched
Figure out how many middleStrings can be there .( You know the first occurance of * , so add +1 to that position and find next occurance of * . this way do till you reach lastst *)
Now simply use substring method for all the string which you have found ( i.e. prefix string,middle strings and sufix string)

- Pragti February 27, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

I do not think this is a perfect algorithm but this is what I could do in the whiteboard.

public static bool IsMatch(string S, string P)
{
	int ppos = 0;
	int spos = 0;
	while(ppos < P.Length && spos < S.Length)
	{
		char p = P[ppos];
		char s = S[spos];

		if(p == s || p == '.')
		{
			ppos++;
			spos++;
		}
		else if(p == '*')
		{
			if(ppos < P.Length - 1 && s == P[ppos + 1])
			{
				spos++;
				ppos += 2;
			}
			else if(ppos > 0 && (s == P[pos - 1] || P[ppos-1] == '.'))
			{
				spos++;
			}
			else
				return false;
		}
		else 
			return false;
		
	}

	return (ppos == P.Length && spos == P.Length);
}

- Nelson Perez March 06, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

function func($pattern,$string) {
	if (strpos($pattern,"**") !== false || strpos($pattern,"*") === 0) 
		return false;

	$pi = 0;
	$si = 0;
	do {
		$p_chr = $pattern[$pi];
		$s_chr = $string[$si];

		if ($p_chr == $s_chr || $p_chr == '.') {
			$pi++;
			$si++;
		} elseif ($p_chr == '*') {	
			$masterChar = $string[$si-1];
			while ($string[$si] == $masterChar) $si++;
			$pi++;
		} elseif ($pattern[$pi+1] == '*') {
			$pi+=2;
		} else {
			return false;
		}

	}while($p_chr != null || $s_char != null);
	
	return true;
}

var_dump(func("aaa","aaa") == true);
var_dump(func("aaak","aaa") == false);
var_dump(func("aaa","aaak") == false);
var_dump(func("a.a","ana") == true);
var_dump(func(".aa.","jaan") == true);
var_dump(func("aaa","bbb") == false);
var_dump(func(".aa","bbb") == false);
var_dump(func("ab*g","ag") == true);
var_dump(func("ab*g","abg") == true);
var_dump(func("ab*g","abbg") == true);
var_dump(func("ab*","abbb") == true);
var_dump(func("b*","") == true);
var_dump(func(".*.","jjjjjm") == true);
var_dump(func("*aaa","a") == false);
var_dump(func("aa***a","a") == false);
var_dump(func(".","j") == true);

- giladsoffer February 13, 2014 | Flag Reply


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More