Facebook Interview Question for Software Engineer / Developers


Country: United States
Interview Type: In-Person




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

The question clearly states ' return an array of all possible mutations'. This means that both time AND space must be linear in the size of the output. The point is, what is the size of the output in terms of the input.

Lets just look at the worst-case complexity, since average case is hard to even define, let alone analyse. Say the input string is of size n. The worst case is that every character has a mapping. Lets also say that all mappings have arrays of the same size, m (that is, all arrays are the longest possible arrays for that mapping). Then the number of outputs we have is n^m, which is huge.

In simple terms I can't see any way to optimise this. However, you could return a data structure like this (for the given example):

[
[f, F, 4],
[a],
[b, B, 8]
]

ie an array of arrays, where every subarray is the corresponding character, together with its mapped mutations if there are any. You could then create an iterator that uses that data structure to produce the next mutated output string from each call to next().

- tom February 19, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

"Return an array" is most likely what the interviewee interpreted and not the actual question.

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

" Say the input string is of size n. The worst case is that every character has a mapping. Lets also say that all mappings have arrays of the same size, m (that is, all arrays are the longest possible arrays for that mapping). Then the number of outputs we have is n^m, which is huge. "

that's not true, you have to raplace at max 26 symbols(or 52, or how many different characters could be in input string) so complexity is 26 ^ m(where m is an average length of maping)

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

sorry m ^ 26

- Anonymous March 11, 2014 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

Treat is like an odometer: [3,1,3]. Start with [0,0,0] -> [1,0,0] -> [2,0,0] ->[0, 0, 1] -> [1,0,1] etc. (read from right to left instead left to right).

This little space (as compared to creating lists and appending).

Here is some python code:

def generate_odometer(limits_list):
	odometer_list = map(lambda x: 0, limits_list)
	has_more = True
	n = len(odometer_list)
	while has_more:
		yield odometer_list
		has_more = False
		for j in range(0,n):
			limit = limits_list[j]
			if odometer_list[j] < limit-1:
				odometer_list[j] = odometer_list[j]+1
				has_more = True
				break
			else:
				odometer_list[j] = 0;
				continue
  
def generate_mutations(string, hashmap):
	limits_list  = map(lambda c: 1 + len(hashmap[c]) if c in hashmap else 1, string)
	for odometer in generate_odometer(limits_list):
		yield odometer_string(odometer, string, hashmap) 
  
def odometer_string (odometer, string, hashmap):
	chars = map (lambda idx, ch: ch if idx == 0 else hashmap[ch][idx -1], 
			odometer, string)
	return ''.join(chars)
  	
def main():
	hashmap = {'f':['F', '4'], 'b': ['B', '8']}
	for s in generate_mutations('fab', hashmap):
		print s

output is

fab
Fab
4ab
faB
FaB
4aB
fa8
Fa8
4a8

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

could you please explain, what is the time and space compexity of this solution??

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

@goutham: Space complexity is O(S) where S is the length of string. (In case of 'fab', S is 3).

Time complexity is linear in the output size (which is optimal).

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

Note that using yield gives you a lazy iteration. You can actually print just the first 5 if you want.

In that case, space complexity is O(S) and time complexity in again linear in size of output (for print just the first 5).

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

@goutham Time complexity is always expressed in terms of input size. If we express a problem like this in terms of output it's always linear and doesn't tell us much.

This is a string/sequence problem. So in this problem, ignoring letters that aren't in the hash map (since they don't change), there are n^m combinations of possible words, where n is the number of variable positions and m is the number of possible values for each. In other words the complexity is O(n^m), which is the expected complexity of generating all sequences of length m from n items. In this case it's 2^3 = 8 words.

However if the number of possible values is different for each position (e.g if "f" had m1 substitutes and "b" had m2), I think the complexity is O(n^(max(m1,m2))) but I'm not 100% certain.

- Barry Fruitman March 16, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

@barry, its 3*1*3 = 3^2 =9 not 2^3 = 8

and in other case it'll be O(m1*1*m2) complexity, no n there

given below working php code for this

<?php

$in = array('f', 'a', 'b');
$hash = array(
'f' => array('F', '4'),
'b' => array('B', '8')
);

getPerm($in, $hash);

function getPerm($in, $hash)
{
	permHelper($in,sizeof($in)-1, $hash);
}

function permHelper($in,$i, $hash){
	if($i == -1)
	{
		echo "\n".implode('',$in);
		return;
	}
	
	permHelper($in,$i-1, $hash);
	
	if(isset($hash[$in[$i]]))
	{
		foreach($hash[$in[$i]] as $rep)
		{
			$in[$i] = $rep;
			permHelper($in,$i-1, $hash);			
		}
	}
}

- lolcoder January 04, 2014 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

This is my solution, I think space complexity should be O(n), Since I use backtrack, time complexity is not very well.

My output sequence is different:fab faB fa8 Fab FaB Fa8 4ab 4aB 4a8

import java.util.ArrayList;
import java.util.HashMap;

//Given a hashmap M which is a mapping of characters to arrays of substitute characters,
//and an input string S, return an array of all possible mutations of S
//(where any character in S can be substituted with one of its substitutes in M, if it exists).

public class Permute {

public static ArrayList<String> getMutation(String str, HashMap<Character, char[]> map){
ArrayList<String> result = new ArrayList<String>();
int lens = str.length();
if(lens == 0){
return result;
}
if(map.isEmpty()){
result.add(str);
return result;
}
char[] mutation = new char[lens];
getMutation(str, map, result, mutation, 0);
return result;
}

public static void getMutation(String str, HashMap<Character, char[]> map, ArrayList<String> result, char[] mutation, int index){
if(index == str.length()){
String newItem = new String(mutation);
result.add(newItem);
return;
}

char current = str.charAt(index);
if(map.containsKey(current)){
char[] choice = map.get(current);
for(int i = 0; i <= choice.length;i++){
if(i == 0){
mutation[index] = current;
getMutation(str, map,result, mutation, index+1);
}
else{
mutation[index] = choice[i-1];
getMutation(str, map, result, mutation, index+1);
}
}
}
else{
mutation[index] = current;
getMutation(str, map, result, mutation, index+1);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String in = "fab";
char[] valueOne = new char[2];
char[] valueTwo = new char[2];
HashMap<Character, char[]> map = new HashMap<Character, char[]>();
valueOne[0] = 'F';
valueOne[1] = '4';
valueTwo[0] = 'B';
valueTwo[1] = '8';
map.put('f', valueOne);
map.put('b', valueTwo);
ArrayList<String> result = new ArrayList<String>();
result = getMutation(in, map);
for(String str:result){
System.out.println(str);
}
}
}

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

def substitute(m, s, results=[], prefix=""):
    if not s:
        results.append(prefix)
        return results

    char = s[0]
    if char in m:
        for substitution in m[char]:
            new_prefix = prefix + substitution
            substitute(m, s[1:], results, new_prefix)
    substitute(m, s[1:], results, prefix + s[0])
    return results


M = { "f": ["F", "4"], "b": ["B", "8"] }
S = "fab"
print(substitute(M, S))

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

public void doIt(String s,Map<Character,Character[]> m){
		List<String> results = new ArrayList<String>();
		if(results.add(s));
		for(Character c : s.toCharArray()){
			if(M.containsKey(c)){
				List<String> list = new ArrayList<String>();
				for(Character k : M.get(c)){
					for(String temp : results){
						list.add(temp.replace(c,k));
					}
				}
				results.addAll(list);
			}
		}
		System.out.println(results);

- goutham467 February 15, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Space complexity is size of output, which can be pretty huge.

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

This 'solution' is wrong.

- Chih.Chiu.19 February 22, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

hashmap = {'f':['F', '4'], 'b': ['B', '8']}
def printArray(str,result):
    if str == "":
        print ''.join(result)
    else:
        result.append(str[0])
        printArray(str[1:],result);
        result.pop()
        c = hashmap.get(str[0])
        if c != None:
            for r in c:
                result.append(r)
                printArray(str[1:],result);
                result.pop()
printArray("fab",[])

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

Space.....

- James T Kirk. February 17, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

(function(content, htReplaceCharacters) {
    function mutate(content, index, htReplaceCharacters, result) {
        for (var i = index; i < content.length; ++i) {
            var character = content.charAt(i);

            var replaceCharacters = htReplaceCharacters[character];

            if (replaceCharacters) {
                for (var j = 0; j < replaceCharacters.length; ++j) {
                    var replaceCharacter = replaceCharacters[j];

                    var tmp = content.substr(0, i) + replaceCharacter + content.substr(i + 1);

                    result.push(tmp);

                    mutate(tmp, i + 1, htReplaceCharacters, result);
                }
            }
        }
    }

    var result = [];

    mutate(content, 0, htReplaceCharacters, result);

    result.push(content);

    console.log(result);  // "Fab", "FaB", "Fa8", "4ab", "4aB", "4a8", "faB", "fa8", "fab"
}(
    'fab',
    {
        'f': ['F', 4],
        'b': ['B', 8]
    }
));

- Ed March 03, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

The code above is JavaScript, run it in node.js

- Ed March 03, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Does anybody know the time complexity of this problem if "f" and "b" had a different number of substitutes?

- Barry Fruitman March 16, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

My solution in Java. The time complexity is O(n^m) where n is the number of variable positions (in this case 2, f and b) and m is the number of possible values (in this case 3 for each, the letter + its substitutes).

The complexity is exponential but I don't believe we can improve on it since we are required to generate n^m output strings.

import java.util.HashMap;
import java.util.ArrayList;


public class Substitutes {

	private static HashMap<String,ArrayList<String>> substitutesMap = new HashMap<String,ArrayList<String>>();
	
	private static void permute(String permutation, String input, int pos) {
		if(pos == input.length()) {
			System.out.println(permutation);
			return;
		}

		String letter = input.substring(pos,pos+1);
		
		ArrayList<String> substitutes = new ArrayList<String>();
		substitutes.add(letter);
		if(substitutesMap.get(letter) != null)
			substitutes.addAll(substitutesMap.get(letter));

		for(String substitute : substitutes)
			permute(permutation + substitute, input, pos+1);
	}
	
	
	
	/*
	 * TEST HARNESS
	 */
	
	static {
		 ArrayList<String> f = new ArrayList<String>();
		 f.add("F");
		 f.add("4");

		 ArrayList<String> b = new ArrayList<String>();
		 b.add("B");
		 b.add("8");
		 
		 substitutesMap.put("f", f);
		 substitutesMap.put("b", b);
	};


	public static void main(String args[]) {
		permute("", "fab", 0);
	}
}

- Barry Fruitman March 16, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

my two cents in python; i think time complexity would depend on both the size of the hashtable and the size of the input. space complexity is the same?

for i in range(len(S)):
  if i == 0:
    Oldlist = [S[i]]
    if S[i] in M:
      for j in range(len(M[S[i]])):
        Oldlist.append(M[S[i]][j])
  else:
    Newlist = []
    for m in range(len(Oldlist)):
      Newlist.append(Oldlist[m]+S[i])
      if S[i] in M:
        for n in range(len(M[S[i]])):
          Newlist.append(Oldlist[m]+M[S[i]][n])
    Oldlist = Newlist

print Oldlist

- Anonymous June 11, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static void printMutation(Map<Character, String> map, String str,
	    char[] ret, int cursor)
    {
	if (cursor == str.length())
	{
	    System.out.println(ret);
	    return;
	}

	Character ch = str.charAt(cursor);
	ret[cursor] = ch;
	printMutation(map, str, ret, cursor + 1);

	String mapped = map.get(ch);
	if (map.containsKey(ch))
	{
	    for (int j = 0; j < mapped.length(); j++)
	    {
		ret[cursor] = mapped.charAt(j);
		printMutation(map, str, ret, cursor + 1);
	    }
	}
    }

- Anonymous June 16, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

O(ans.count) time and O(ans.size) space complexity:

static List<string> GenerateSubstitutions(string str, Dictionary<char, string> map)
{
    List<string> result = new List<string>();
    StringBuilder sb = new StringBuilder(str);
    Action<int> rec = null;
    rec = pos =>
        {
            if (pos >= sb.Length) result.Add(sb.ToString()); 
            else
                if (!map.ContainsKey(str[pos])) rec(pos + 1);
                else
                {
                    rec(pos + 1);
                    foreach (var c in map[str[pos]])
                    {
                        sb[pos] = c;
                        rec(pos + 1);
                    }
                }
        };
    rec(0);
    return result;
}

- Flux October 22, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

There is also a tricky solution with very good time and space complexities. We do not have any restrictions about output format of resultant word set, so it will be absolutely legal to output them as a trie. The main idea of algorithm is following:
Given a source string and map of substitutions, let's construct a trie with a single word - source string:

(start)
       |
      (f)
       |
       |
      (a)
       |
       |
      (b)
       |
     (end)

Now, lets iterate over trie nodes. If we see a node with a character that presents in a map, let's transform this node to a cuple of nodes with all possible substitutions for that character, i.e.

|           / | \
 (f) ->  (f)(F)(4) 
  |        \ | /

Applying this procedure to all nodes, we will get a trie with all possible substitutions, like

(start)
        / | \
     (f)(F)(4)
        \ | /
          |
         (a)
          |
        / | \
    (b)(B)(8)
      /   |   \
   (end)(end)(end)

So that, in worst case, time and space complexity is O(n*k), where n is length of the string and k is length of longest array in the map of substitutions.

- Flux October 22, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

This code will be ok.

void Trace(std::string & path, std::vector<std::string> & rs, std::map<char, std::string> & dict, int k) {
  if (k == path.size()) {
    rs.push_back(path);
  } else {
    Trace(path, rs, dict, k + 1); 
    char ch = path[k];
    if (dict.count(ch)) {
      for (int i = 0; i < dict[ch].size(); i++) {
        path[k] = dict[ch][i];
        Trace(path, rs, dict, k + 1); 
      }   
      path[k] = ch; 
    }   
  }
}

std::vector<std::string> Trace(std::string & str, std::map<char, std::string> & dict) {
  std::vector<std::string> rs; 
  Trace(str, rs, dict, 0); 
  return rs; 
}

- guoliqiang2006 December 31, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

<?php

$in = array('f', 'a', 'b');
$hash = array(
'f' => array('F', '4'),
'b' => array('B', '8')
);

getPerm($in, $hash);

function getPerm($in, $hash)
{
	permHelper($in,sizeof($in)-1, $hash);
}

function permHelper($in,$i, $hash){
	if($i == -1)
	{
		echo "\n".implode('',$in);
		return;
	}
	
	permHelper($in,$i-1, $hash);
	
	if(isset($hash[$in[$i]]))
	{
		foreach($hash[$in[$i]] as $rep)
		{
			$in[$i] = $rep;
			permHelper($in,$i-1, $hash);			
		}
	}
}

- lolcoder January 04, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static void main(String[] args){
     Collection<String> results = new HashSet<>();
     getMutatedString(input, replacementMap, results);
     System.out.println(results);
}
static void getMutatedString(String input, Map<Character, List<Character>> replacements, Collection<String> results) {
		results.add(input);
		for (Character c : input.toCharArray()) {
			replacements.forEach((k, v) -> {
				if (c == k) {
					Set<String> temp = new LinkedHashSet<>();
					v.forEach(r -> results.forEach(result -> temp.add(result.replace(c, r))));
					results.clear();
					results.addAll(temp);
				}
			});
		}
	}

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

public class Solution{
	private static Map<Character, List<Character>> replacements = new HashMap<>();

	static {
		replacements.put('f', ImmutableList.of('F', '4'));
		replacements.put('b', ImmutableList.of('B', '8'));
	}
	static void getMutatedStrings(String input, Collection<String> results) {
		results.add(input);
		for (Character c : input.toCharArray()) {
			replacements.forEach((k, v) -> {
				if (c == k) {
					Set<String> temp = new LinkedHashSet<>();
					v.forEach(r -> results.forEach(result -> temp.add(result.replace(c, r))));
					results.clear();
					results.addAll(temp);
				}
			});
		}
	}

	public static void main(String[] args) {
		Collection<String> results = new LinkedHashSet<>();
		String input = "fab";
		getMutatedStrings(input, results);
		System.out.println(results);
	}
}

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

public class Solution{
	private static Map<Character, List<Character>> replacements = new HashMap<>();

	static {
		replacements.put('f', ImmutableList.of('F', '4'));
		replacements.put('b', ImmutableList.of('B', '8'));
	}
	static void getMutatedStrings(String input, Collection<String> results) {
		results.add(input);
		for (Character c : input.toCharArray()) {
			replacements.forEach((k, v) -> {
				if (c == k) {
					Set<String> temp = new LinkedHashSet<>();
					v.forEach(r -> results.forEach(result -> temp.add(result.replace(c, r))));
					results.clear();
					results.addAll(temp);
				}
			});
		}
	}

	public static void main(String[] args) {
		Collection<String> results = new LinkedHashSet<>();
		String input = "fab";
		getMutatedStrings(input, results);
		System.out.println(results);
	}
}

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

public static void printUtil(String input, Map<Character, Object[]> map, int ci) {
        System.out.println(input);
        if (ci >= input.length()) return;

        Object next = map.get(input.charAt(ci));
        if (next != null) {
            Object[] nextArr = (Object[]) next;
            for(int j=ci+1;j<=input.length();j++) {
                for (int i = 0; i < nextArr.length; i++) {
                    printUtil(input.substring(0,ci)+nextArr[i]+input.substring(ci+1), map, j);
                }
            }
        }
    }

    public static void print(String input, Map<Character, Object[]> map) {
//        for(int i=0;i<input.length();i++) {
            printUtil(input, map, 0);
//        }
    }

    public static void main(String[] args) {
        Map<Character, Object[]> map = new HashMap<>();
        map.put('f', new Object[]{'F', '4'});
        map.put('b', new Object[]{'B', '8'});
        print("fab", map);
    }

- Siddhi Parkar March 20, 2018 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

Time is O(N) where N is input="fab", but how many operations we have to execute?
In the worst case it is O(N*M), where M=max_length{{ 'F', '4' }, { 'B', '8' }, ...} so it is better to say that time is O(N*M).

public static void main(String[] args) {

        Map<Character, char[]> map = new HashMap<Character, char[]>();
        map.put('f', new char[] { 'F', '4' });
        map.put('b', new char[] { 'B', '8' });

        final String input = "fab";

        // expect
        // [fab, Fab, 4ab, faB, FaB, 4aB, fa8, Fa8, 4a8]

        List<String> output = new ArrayList<String>();

        mutations(map, input, 0, output);

        // get
        // [fab, faB, fa8, Fab, FaB, Fa8, 4ab, 4aB, 4a8]
        System.out.println(output);
    }

    private static void mutations(Map<Character, char[]> map, String input, int pos, List<String> output) {
        if (pos == input.length()) {
            output.add(input);
            return;
        }

        // process 'f'
        mutations(map, input, pos + 1, output);

        // process ['F', '4']
        char ch = input.charAt(pos);
        if (map.containsKey(ch)) {
            for (char substitute : map.get(ch)) {
                input = input.replace(ch, substitute);
                mutations(map, input, pos + 1, output);
            }
        }
    }

- Anonymous March 20, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
-2
of 2 vote

This is a variation of telephone words:

public static void main(String[] args) {

	Map<Character, char[]> map = new HashMap<Character, char[]>();
	map.put('f', new char[] { 'F', '4' });
	map.put('b', new char[] { 'B', '8' });
	String s = "fab";
	printStrings(s.toCharArray(), new StringBuilder(), map, 0);
    }

    public static void printStrings(char[] s, StringBuilder sb, Map<Character, char[]> map, int pos) {

	if (sb.length() == s.length) {
	    System.out.println(sb);
	    return;
	}
	char[] subs = map.get(s[pos]);
	sb.append(s[pos]);
	printStrings(s, sb, map, pos + 1);
	sb.setLength(sb.length() - 1);
	if (subs != null) {
	    for (int i = 0; i < subs.length; i++) {
		sb.append(subs[i]);
		printStrings(s, sb, map, pos + 1);
		sb.setLength(sb.length() - 1);
	    }
	}
    }

- thelineofcode July 24, 2013 | 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