Facebook Interview Question for iOS Developers


Country: United States
Interview Type: Phone Interview




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

For each word in the array, sort it and then store it in a hash table. As soon as you encounter a word whose sorted version exists in the hash table, that means we have found a anagram.

- prd April 23, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

You don't even need to sort the characters in the words - just store them in a multiset (one per word) and put these multisets to a hashtable to reach O(n).

- Danstahr April 23, 2014 | Flag
Comment hidden because of low score. Click to expand.
-2
of 2 votes

For word "open" & "oepn", they're same after sorted, but they are not anagram.

- koegent April 23, 2014 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

These two ARE anagrams.

- Danstahr April 23, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

koegent, aka GEEK NOT?

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

Oh, sorry, it's my fault.
What I meant is "palindrome", not anagrams.

The question asks for "anagrams".

- koegent April 25, 2014 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

@Danstahr : Could you please elaborate on the multiset solution?

- prd April 23, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

Provided it's related to OS X or iOS and the power of Foundation can be used:

@import Foundation;

BOOL containsAnnagrams(NSArray* words) {
  NSMutableSet* characterSets = [NSMutableSet set];
  for (NSString* word in words) {
    NSCharacterSet* characterSet = [NSCharacterSet characterSetWithCharactersInString:word];
    if ([characterSets containsObject:characterSet]) {
      return YES;
    }

    [characterSets addObject:characterSet];
  }

  return NO;
}

- vmagaziy April 28, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

The above solution works if there are no duplicate characters.
An anagram should have every characters used exactly once.The below array also gives a result that they are anagrams , but char a has been used twice.

NSArray *ana1 = @[@"bag",@"bat",@"aatb"];

- vinodha88 June 27, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

public class Anagrams {
	
	public static void main(String[] args) {

		String[] arr = new String[] {"bat","cat","tab","put"};
		
		for (int i = 0; i < arr.length; i++) {
			for (int j = 0; j < arr.length; j++) {
				if(i!=j){
					boolean contains = anagrams(arr[j],arr[i]);
							if(contains){
								System.out.println("The string "+ arr[i] + " is anagram of "+ arr[j]);
							}
				}
			}
		}
		
	}

	private static boolean anagrams(String string1, String string2) {
		char[] c1 = string1.toCharArray();
		char[] c2 = string2.toCharArray();
		
		boolean contains = false;
		for (int i = 0; i < c1.length; i++) {
			contains = false;
			for (int j = 0; j < c2.length; j++) {
				if(c2[j] == c1[i]){
					contains = true;
					break;
				}
			}if(!contains){
				break;
			}
		}
		
		return contains;
	}

}

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

I think "tus" and "tush" are not anagrams. But if we give these strings in your function

anagrams("tus","tush") then it will return true

- Tushar Arora April 28, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Hi
Assume list of input Strings {"abc","bcd","bca"}

My answer is find out the hash of each string and check with others if it is equal then both are anagrams.

For example:
"abc" hash is 'a'+'b'+'c' = 97+98+99 = 294
"bcd" hash is 'b'+'c'+'d' = 98+99+100 = 297
"bca" hash is 'b'+'c'+'a' = 98+99+97 = 294
From above example we can conclude that "abc" and "bca" are anagrams

If this is wrong let me.

Thanks

- SRINIVAS April 24, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

"a"+ "d" = "b" + "c" but "ad" and "bc" are not anagrams.

- prd April 24, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

won't work.

"bcd" hash is 'b'+'c'+'d' = 98+99+100 = 297
"ace" hash is 'a'+'c'+'e' = 97+99+101 = 297

- codedore April 26, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

void groupAnagrams(NSArray *array) {
    
    NSMutableDictionary *group = [[NSMutableDictionary alloc] initWithCapacity:[array count]];
    
    for (NSString *s in array) {
        const char *c = [s UTF8String];
        int sum = sumCharacters(c);
        NSMutableArray *anagrams = [group objectForKey:[NSNumber numberWithInt:sum]];
        if (anagrams) {
            [anagrams addObject:s];
        } else {
            NSMutableArray *anagrams = [[NSMutableArray alloc] initWithCapacity:10];
            [anagrams addObject:s];
            [group setObject:anagrams forKey:[NSNumber numberWithInt:sum]];
        }
    }
    
    for (NSNumber *n in group) {
        NSArray *anagrams = [group objectForKey:n];
        printf("[");
        for (NSString *s in anagrams) {
            printf("%s,", [s UTF8String]);
        }
        printf("]\n");
    }
}

int sumCharacters(const char *c) {
    int charValues[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
    int intValues[10] = {103, 107, 109, 113, 127, 131, 137, 139, 149, 151};
    int spaceValue = 157;
    int commaValue = 163;
    
    int sum = 0;
    for (int i=0; c[i] != '\0';i++) {
        if (c[i] >= 'a' && c[i] <= 'z') {
            sum += charValues[c[i] - 'a'];
        } else if (c[i] >='0' && c[i] <= '9') {
            sum += intValues[c[i] - '0'];
        } else if (c[i] == ' '){
            sum += spaceValue;
        } else if (c[i] == ','){
            sum += commaValue;
        }
    }
    
    return sum;
}

- peeterparker April 24, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

In this case of adding characters and using prime numbers to add, I don't see any case arising where two characters are added and that gives another two characters. Please see, I am also checking the length so that 'a' + b' = 'c' but length check wil fail it.

- peeterparker April 24, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

convert "bat" to "a1b1t1", so the algo is:

std::string strtostr(std::string s)
{
	int a[26] = {0};
	int l = s.length();

	for (int i = 0; i < l; ++i)
	{
		a[s[i] - 'a']++;
	}

	std::string result;
	for (int i = 0; i < 26; ++i)
	{
		if (a[i] > 0)
		{
			result += ('a' + i);
			result += ('0' + a[i]);
		}
	}

	return result;
}

bool has_anagrams(std::vector<std::string>& strset)
{
	std::set<std::string> wordset;

	int size = strset.size();
	for (int i = 0; i < size; ++i)
	{
		std::string k = strtostr(strset[i]);
		if (wordset.find(k) != wordset.end())
		{
			return true;
		}
		else
			wordset.insert(k);
	}

	return false;
}

- guest.guest April 25, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

How about this?
list of string -> Map of Integer to List.
For key of this map, I will use hash function which just take ascii value of chars in each string.

It's like pre-processing.
If one of those key has a value of list whose size is bigger than 1, it means that this list 'may' have a candidate of anagram.

In this case, I sort every string in this list, and put them into a 'Set'. If there are collisions,
it means "there is a anagram".

public static boolean checkAnagrams(String[] strings) {
        Map<Integer, List<String>> result = createMap(strings);
        for (int key : result.keySet()) {
            if (result.get(key).size() > 1) {
                Set<String> set = new HashSet<>();
                for (String s : result.get(key)) {
                    char[] target = s.toCharArray();
                    Arrays.sort(target);
                    if (set.contains(new String(target))) {
                        return true;
                    } 
                    set.add(new String(target));
                }
            }
        }
        return false;
    }   
    
    private static Map<Integer, List<String>> createMap(String[] strings) {
        System.out.println("Come to createMap");
        Map<Integer, List<String>> info = new HashMap<>();
        for (String s: strings) {
            int currentHash = getHash(s);
            List<String> results;
            if (info.containsKey(currentHash)) {
                results = info.get(currentHash);
            } else {
                results = new ArrayList<>();
            }
            results.add(s);
            info.put(currentHash, results);
        }
        return info;
    }
    
    private static int getHash(String input) {
        int hashValue = 0;
        for (char c : input.toCharArray()) {
            hashValue += (int) c;
        }
        return hashValue;
    }

- soodongStudying April 28, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

PHP version

function hasAnagrams($stringsArray) {
	// keep a hash of the ordered words
	$stringsOrderedHash = array();

	foreach ($stringsArray as $word) {
		// skip blanks
		if (!$word) {
			continue;
		}

		// lowercase the word, as anagrams should match regardless of case???
		$word = strtolower($word);

		// convert word to array
		$wordArray = str_split($word);

		// sort resultant letters
		sort($wordArray);

		$wordSorted = implode($wordArray);
		
		// key exists, has anagrams
		if (isset($stringsOrderedHash[$wordSorted])) {
			return true;
		}

		// add to hash as key to allow index lookup
		$stringsOrderedHash[$wordSorted] = 1;
	}

	// ran out of words to check, so no anagrams
	return false;
}

- jasonj79 May 02, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

static boolean hasAnagram(String [] list)
	{
		for(int i=0;i<list.length;i++)
		{
			for(int j=0;j<list.length;j++)
			{
				if(i==j);
				
				else
				{
					if(list[i].length()-list[j].length()==0)
					{
						for(int m=0;m<list[i].length();m++)
						{
							for(int n=0;n<list[i].length();n++)
							{
								if(list[i].charAt(m)==list[j].charAt(n))
								{
									count++;
								}
							}
						}
						if(count==list[i].length())
							val=1;
						count=0;
					}	
				}
			}
		}
		if(val==1)
			return true;
		else
			return false;

}

- slimdjim May 06, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

def has_anagram(s):

  n = len(s)

  for i in range(n):
    s[i] = ''.join(sorted(s[i]))

  return len(s) != len(set(s))

print has_anagram(['bag', 'bat', 'tab'])
print has_anagram(['gab', 'bat', 'laf'])

- s7a May 12, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

private static boolean verifyAnagramExistence(String[] str) {
		boolean isAnagramExist = false;
		int[] ascii = new int[str.length];
		int index = 0;
		for(String s : str){
			int value = getAsciiValue(s);
			if(!isAlreadyExist(ascii,value))
				ascii[index++] = value;
			else{
				isAnagramExist = true;
				break;
			}
		}
		return isAnagramExist;
	}

	private static int getAsciiValue(String s) {
		int sum = 0;
		for(char ch : s.toCharArray()){
			sum += String.valueOf(ch).codePointAt(0);
		}
		return sum;
	}
	
	private static boolean isAlreadyExist(int[] ascii, int value) {
		for(int number : ascii){
			if(number == value)
				return true;
		}
		return false;
	}

- kmlsharma53 June 22, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

1. Assign a prime number to each letter (a = 2, b = 3, c = 5, ...)
2. For each word compute the hash as the product of the prime numbers associated with each letter
3. Store the hash in a set - if it's already there, you have anagrams

Time: O(n), where n is the number of letters, Space: O(n), where n is the number of words.

- meh July 01, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public class TestProgram {

	static final String[] INPUT_ARRAY = { "bag", "bat", "tab" };

	// static final String[] INPUT_ARRAY = {"gab","bat","laf"};

	public static void main(String[] args) {
		boolean result = false;
		for (int i = 0; i < INPUT_ARRAY.length - 1; i++) {
			StringBuilder word = new StringBuilder(INPUT_ARRAY[i]);
			StringBuilder nextWord = new StringBuilder(INPUT_ARRAY[i + 1]);
			if (word.length() != nextWord.length())
				continue;
			for (int j = 0; j < word.length();) {
				String chr = word.charAt(j) + "";

				int index = nextWord.indexOf(chr);
				if (index == -1)
					break;
				word.deleteCharAt(j);
				nextWord.deleteCharAt(index);
			}

			if (word.length() == 0) {
				result = true;
				break;
			}
		}
		System.out.println(String.valueOf(result).toUpperCase());
	}

}

- Mohit Mehta July 02, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

This is what i think can be a good match for ios.

BOOL isAnagram(NSArray *input) {
  NSMutableDictionary *anagrams = [NSMutableDictionary dictionary];
  __block BOOL isAnagram = NO;
  [input enumerateObjectsUsingBlock:^(NSString *word, NSUInteger idx, BOOL *stop) {
    NSMutableArray *characters = [NSMutableArray array];
    for (NSUInteger i = 0; i < word.length; i++) {
      [characters addObject:[word substringWithRange:NSMakeRange(i,1)]];
    }
    // now sort the word
    NSArray *sortedCharacters = [characters sortedArrayUsingSelector:@selector(compare:)];
    NSString *sortedWord = [sortedCharacters componentsJoinedByString:@""];
    if (anagrams[sortedWord] != nil) {
      isAnagram = YES;
      *stop = YES;
    } else {
        anagrams[sortedWord] = sortedWord;
    }
  }];
  
  return isAnagram;
  
}


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSArray *input = @[@"bag", @"bat", @"tab"];
      if (isAnagram(input)) {
        NSLog(@"input is anagram");
      } else {
          NSLog(@"no Anagrams");
      }
    }
    return 0;
}

can't find a better way to get the characters out

- crisredfi1 July 08, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

def has_anagrams(input):
    for word in input:
        if word[::-1] in input:
            return True
    return False

- James August 22, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Use a hash map to store the normalized version of a word, which is (char->count). Use a hash set to store all the normalized (char->count) pairs. The hash set need to implement a Comparator<Map<Char, Integer>> interface to tell if two hash maps have the same key set and count sets. The function can return true at first occurrence of matching hash maps. Time complexity is O(n), space complexity is O(n).

- sabz August 24, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public static void main(String[] args){

		String[] s={"bak","bag","tab"};
		System.out.println(solve(s));
		
	}	
	
	static boolean solve(String[] s){

		
		for(int i=0;i<s.length;i++){
			String tmp=new StringBuilder(s[i]).reverse().toString();
			for(int j=0;j<s.length;j++){
				if(i==j)
					continue;
				
				if(tmp.equals(s[j]))
					return true;
				else
					continue;
			}
		}
		return false;
	
			
	}

- Youngsam September 16, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

- (BOOL)arrayContainsAnagrams:(NSArray*)arrayOfWords
{
    BOOL containsAnagrams = FALSE;
    
    for (NSString *word in arrayOfWords)
    {
        for (NSString *anotherWord in arrayOfWords)
        {
            if ((word != anotherWord) && (word.length>0) && (word.length == anotherWord.length))
            {
                BOOL foundAllLetters = TRUE;
                
                for (int a = 0; a < word.length; a++)
                {
                    NSString *subString = [word substringWithRange:NSMakeRange(a, 1)];
                    
                    if ([anotherWord rangeOfString:subString].location == NSNotFound)
                    {
                        foundAllLetters = FALSE;
                        break;
                    }
                    
                }
                containsAnagrams = foundAllLetters;
                    
            }
        }
    }
    
    return containsAnagrams;
}

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

- (BOOL)arrayContainsAnagrams:(NSArray*)arrayOfWords
{
    BOOL containsAnagrams = FALSE;
    
    for (NSString *word in arrayOfWords)
    {
        for (NSString *anotherWord in arrayOfWords)
        {
            if ((word != anotherWord) && (word.length>0) && (word.length == anotherWord.length))
            {
                BOOL foundAllLetters = TRUE;
                
                for (int a = 0; a < word.length; a++)
                {
                    NSString *subString = [word substringWithRange:NSMakeRange(a, 1)];
                    
                    if ([anotherWord rangeOfString:subString].location == NSNotFound)
                    {
                        foundAllLetters = FALSE;
                        break;
                    }
                    
                }
                containsAnagrams = foundAllLetters;
                    
            }
        }
    }
    
    return containsAnagrams;
}

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

boolean solve(String[] input) {
    Set<String> dict = Sets.newHashSet();

    for (String elem : input) {
      char[] array = elem.toCharArray();
      Arrays.sort(array);
      String target = new String(array);
      if (dict.contains(target)) {
        return true;
      } else {
        dict.add(target);
      }
    }

    return false;
  }

- rachitisthere October 20, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

NSArray *givenArray1 = @[@"bag", @"bat", @"tab"];
    NSMutableArray *reversedArray = [NSMutableArray new];
    
    [givenArray1 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSString *currentString = obj;
        NSMutableString *reversedString = [NSMutableString new];
        [currentString enumerateSubstringsInRange:NSMakeRange(0, currentString.length) options:NSStringEnumerationByComposedCharacterSequences|NSStringEnumerationReverse usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
            [reversedString appendString:substring];
        }];
        [reversedArray addObject:reversedString];
    }];
    
    NSString *foundValue = [givenArray1 firstObjectCommonWithArray:reversedArray];
    if (foundValue) {
        return YES;
    }else{
        return NO;
    }

- deepak.hebbar November 17, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

I think what you're doing here is finding palindromes and not anagrams, am I correct?
(btw, the use firstObjectCommonWithArray is great in this situation!)

- Sydney March 05, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Compute a character frequency table from the first word, then check that every other word creates the same table;

int *charFrequencyTable(const char *s, int len) {
  int *charTable = (int*) malloc(256 * sizeof(int));
  int i;
  for (i = 0; i < 256; i++) {
    charTable[i] = 0;
  }
  for (i = 0; i < len; i++) {
    charTable[i]++;
  }
  return charTable;
}

small int equalCharTables(int *t1, int *t2, int len) {
  int i;
  for (i = 0; i < len; i++) {
    if (t1[i] != t2[i]) return 0;
  }
  return 1;
}

small int isSetOfAnagramas(char **strings, int *lengths, int setLen) {
  int i, areAnagrams;
  int *firstCharTable, *otherCharTable;

  if (setLen <= 1) return 1;

  firstCharTable = charFrequencyTable(strings[0], lengths[0]);
  areAnagrams = 1;

  for (i = 1; i < setLen; i++) {
    otherCharTab = charFrequencyTable(strings[i], lengths[i]);
    if (! equalCharTables(firstCharTable, otherCharTab) {
      areAnagrams = 0;
      break;
    }
  }
  free(firstCharTable);
  free(otherCharTab);
  return areAnagrams;
}

As for the time complexity:
- you have to go through all strings => n strings
- for each string n_i, you have to go through all characters => len(n_i)
- you have to compare first string with all others => n - 1 comparisons
- for each comparison, you have to go through frequency table => len(alphabet)

So crunching those numbers, you get O(n * len(n_i) + (n - 1) * len(alphabet)).
Lengths of words and alphabet might not be larger than a certain valie, but they do add up to the complexity.

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

Ruby O(n) solution with O(n) extra space. First attempt overlooked the opportunity to return true as soon as the first anagram is encountered.

require 'set'

def anagrams(array)
	set = Set.new

	for word in array
		sorted = word.chars.sort.join
		if set.include? sorted
			return true
		else
			set << sorted
		end
	end

	false
end

puts anagrams(["bag","bat","tab"]) # true
puts anagrams(["gab","bat","laf"]) # false

- fungled January 15, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Here is another solution in Objective C running in O(N)

char * toChar(NSString* str){
    const char* strUtf8 	= [str UTF8String];
    size_t len          		= strlen(strUtf8) + 1;
    char *toChar        	= malloc(len);
    memcpy(toChar, strUtf8, len);
    return toChar;
}

NSString* stringReverse(NSString* str){
    char *cWord 	= toChar(str);
    size_t len  		= strlen(cWord);
    int start   		= 0;
    int end     		= (int)len-1;
    while (start<end) {
        cWord[start]    ^= cWord[end];
        cWord[end]     ^= cWord[start];
        cWord[start]    ^= cWord[end];
        start++;
        end--;
    }
    char reverseData[len];
    memcpy(reverseData, cWord, len);
    NSString *reverse = [[NSString alloc] initWithBytes:reverseData
                                                length:sizeof(reverseData)
                                              encoding:NSUTF8StringEncoding];
    return reverse;
}

BOOL hasAnagram(NSArray * array){
    NSMutableSet *set = [NSMutableSet new];
    for(int i=0; i<array.count; i++){
        if([set containsObject:array[i]])
            return YES;
        else
            [set addObject:stringReverse(array[i])];
    }
    return NO;
}

int main(int argc, char *argv[]) {
	@autoreleasepool {
		NSArray *ar = @[@"bag", @"bat", @"tab"];
		NSLog(@"Has anagram: %@", (hasAnagram(ar))?@"true":@"false");
		ar = @[@"gab", @"bat", @"laf"];
		NSLog(@"Has anagram: %@", (hasAnagram(ar))?@"true":@"false");
	}
}

- stefanlage February 12, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

This solution fails if the array "bag", "bat", and "tab" were instead "bag", "bat", "bta" which still has an anagram.

- Dan April 05, 2015 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

@interface AnagramTest : NSObject
  - (BOOL)containsAnagrams:(NSArray*)wordSet;
  - (NSMutableArray*)arrayFromString:(NSString*)myString;
@end
  
@implementation AnagramTest

  - (BOOL)containsAnagrams:(NSArray*)wordSet{
    NSMutableArray *sets = [[NSMutableArray alloc] init];
    for(NSString *word in wordSet){
      NSArray *wordArray = [self arrayFromString:word];
      wordArray = [wordArray sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
      if(![sets containsObject:wordArray]){
        [sets addObject:wordArray];
      }
      else{
        return YES;
      }
    }
    return NO;
  }

  - (NSMutableArray*)arrayFromString:(NSString*)myString{
    NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[myString length]];
    for (int i=0; i < [myString length]; i++) {
        NSString *ichar  = [NSString stringWithFormat:@"%c", [myString characterAtIndex:i]];
        [characters addObject:ichar];
    }
    return characters;
  }

@end

int main (int argc, const char * argv[])
{
  @autoreleasepool {
    AnagramTest *test = [[AnagramTest alloc] init];
    NSArray *words = @[@"bad",@"tab",@"bat"];
    NSLog(@"Set %@ anagrams",[test containsAnagrams:words] ? @"contains":@"doesn't contain");;
  }
}

- Daniel Burke February 26, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

@interface AnagramTest : NSObject
  - (BOOL)containsAnagrams:(NSArray*)wordSet;
  - (NSMutableArray*)arrayFromString:(NSString*)myString;
@end
  
@implementation AnagramTest

  - (BOOL)containsAnagrams:(NSArray*)wordSet{
    NSMutableArray *sets = [[NSMutableArray alloc] init];
    for(NSString *word in wordSet){
      NSArray *wordArray = [self arrayFromString:word];
      wordArray = [wordArray sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
      if(![sets containsObject:wordArray]){
        [sets addObject:wordArray];
      }
      else{
        return YES;
      }
    }
    return NO;
  }

  - (NSMutableArray*)arrayFromString:(NSString*)myString{
    NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[myString length]];
    for (int i=0; i < [myString length]; i++) {
        NSString *ichar  = [NSString stringWithFormat:@"%c", [myString characterAtIndex:i]];
        [characters addObject:ichar];
    }
    return characters;
  }

@end

int main (int argc, const char * argv[])
{
  @autoreleasepool {
    AnagramTest *test = [[AnagramTest alloc] init];
    NSArray *words = @[@"bad",@"tab",@"bat"];
    NSLog(@"Set %@ anagrams",[test containsAnagrams:words] ? @"contains":@"doesn't contain");;
  }
}

- Daniel Burke February 26, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;

public class CostumCompare implements Comparator<String>{

public static String SortedString(String s){
char [] sa = s.toCharArray();
Arrays.sort(sa);
return new String(sa);
}


@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub

return this.SortedString(o1).compareTo(this.SortedString(o2));
}

public static void main(String[] args) {
// TODO Auto-generated method stub

HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();

String [] input = {"test","etst","test2","tesst","test"};

for(String s: input){
String sorted = CostumCompare.SortedString(s);
if(hm.containsKey(sorted)){
hm.get(sorted).add(s);
}else{
hm.put(sorted, new ArrayList<String>());
hm.get(sorted).add(s);
}
}


for(String a:hm.keySet()){
System.out.println(hm.get(a));
}

}

- hs April 02, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Generate a identity for each word based on counted bit vector.

#import <Foundation/Foundation.h>

@interface BitVectorWithOccurences : NSObject <NSCopying>

@property (nonatomic) NSUInteger count;

- (void)setBitVectorByIndex:(CFIndex)index;
- (UInt8)getSetCountByIndex:(CFIndex)index;

- (void)reset;

@end



#import "BitVectorWithOccurences.h"

static const NSUInteger kBitVectorWithOccurencesCountDefault = 26;
static const NSUInteger kBitsPerByte = 8;

@interface BitVectorWithOccurences ()

@property (nonatomic) CFMutableBitVectorRef bitVector;

@end

@implementation BitVectorWithOccurences

- (instancetype)init {
if (self = [super init]) {
_bitVector = CFBitVectorCreateMutable(NULL, 0);
self.count = kBitVectorWithOccurencesCountDefault;

}
return self;
}

- (void)setCount:(NSUInteger)count {
if (_count != count) {
_count = count;
[self reset];
}
}

- (void)reset {
CFIndex bitsPerUnit = sizeof(UInt8) * kBitsPerByte;
CFBitVectorSetCount(_bitVector, bitsPerUnit * _count);
CFBitVectorSetAllBits(_bitVector, 0);
}

- (void)setBitVectorByIndex:(CFIndex)index {
[self addCountAtIndex:index countForSetBits:0];
}

- (UInt8)getSetCountByIndex:(CFIndex)index {
CFIndex bitsPerUnit = sizeof(UInt8) * kBitsPerByte;
UInt8 count = 0;
CFBitVectorGetBits(_bitVector, CFRangeMake(index * bitsPerUnit, bitsPerUnit), &count);
return count;
}

- (void)addCountAtIndex:(CFIndex)index countForSetBits:(NSUInteger)count {
CFIndex bitsPerUnit = sizeof(UInt8) * kBitsPerByte;
if (count < bitsPerUnit) {
CFBit bit = CFBitVectorGetBitAtIndex(_bitVector, (index + 1) * bitsPerUnit - count - 1);
CFBit valueToSet = 1 ^ bit;
CFBitVectorSetBitAtIndex(_bitVector, (index + 1) * bitsPerUnit - count - 1, valueToSet);
if (valueToSet == 0) {
[self addCountAtIndex:index countForSetBits:count + 1];
}
} else {
[NSException raise:@"" format:@"Set index so many times!"];
}
}

- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[self class]]) {
BitVectorWithOccurences *another = (BitVectorWithOccurences *)object;
if (_count == another.count) {
UInt8 selfByte = 0, anotherByte = 0;
for (NSInteger idx = 0; idx < _count; idx++) {
CFIndex bitsPerUnit = sizeof(UInt8) * kBitsPerByte;
CFBitVectorGetBits(_bitVector, CFRangeMake(idx * bitsPerUnit, bitsPerUnit), &selfByte);
CFBitVectorGetBits(another->_bitVector, CFRangeMake(idx * bitsPerUnit, bitsPerUnit), &anotherByte);
if (selfByte != anotherByte) {
return NO;
}
}
return YES;
}
}
return NO;
}

- (NSString *)description {
NSMutableString *bits = [NSMutableString stringWithString:@""];
NSUInteger countUnits = 0;
NSUInteger bitsPerUnit = sizeof(UInt8) * kBitsPerByte;
for (CFIndex i = 0; i < CFBitVectorGetCount(_bitVector); i++) {
CFBit bit = CFBitVectorGetBitAtIndex(_bitVector, i);
if (bit == 1) {
[bits appendString:@"1"];
} else {
[bits appendString:@"0"];
}
countUnits++;
if ((countUnits % bitsPerUnit) == 0) {
[bits appendString:@"|"];
}
}
return [bits copy];
}

- (id)copyWithZone:(nullable NSZone *)zone {
BitVectorWithOccurences *bitVector = [BitVectorWithOccurences new];
bitVector.count = _count;
bitVector->_bitVector = CFBitVectorCreateMutableCopy(NULL, 0, _bitVector);
return bitVector;
}

@end



void main() {
NSArray *wordArray1 = @[@"bag", @"bat", @"tab"];
NSArray *wordArray2 = @[@"gab", @"bat", @"laf"];
NSLog(@"%d", [self containsAnagrams:wordArray1]);
NSLog(@"%d", [self containsAnagrams:wordArray2]);
}

- (BOOL)containsAnagrams:(NSArray *)wordArray
{
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:wordArray.count];
__block BOOL found = NO;
[wordArray enumerateObjectsUsingBlock:^(NSString * _Nonnull word, NSUInteger idx, BOOL * _Nonnull stop) {
BitVectorWithOccurences *bitVector = [self wordIdentity:word];
NSArray *array = [dict objectForKey:bitVector];
if (array.count) {
found = YES;
*stop = YES;
} else {
[dict setObject:[NSMutableArray arrayWithObject:word] forKey:bitVector];
}
}];
return found;
}

- lingguang1997 September 27, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

-(void)findAnagram
{
NSArray *valuesList =[[NSArray alloc]initWithObjects:@"bat",@"cat",@"sdf",@"tab", nil];
NSMutableArray *countList =[[NSMutableArray alloc]init];
for (int k=0; k<valuesList.count; k++) {
NSString *string = [valuesList objectAtIndex:k];
int total = 0;
for(int i=0;i<string.length;i++)
{
NSString *singleChar = [string substringWithRange:NSMakeRange(i, 1)];
int charValue = [singleChar characterAtIndex:0];
total = total + charValue;
}
if ([countList containsObject:[NSString stringWithFormat:@"%d",total]]) {
NSLog(@"Found");
break;
}
else
{
[countList addObject:[NSString stringWithFormat:@"%d",total]];
}
}
}

- Venkat Naresh December 24, 2015 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Swift

func containsAnagram(arr: [String]) -> Bool {
    for word in arr {
        let reverse = String(word.characters.reverse())
        if arr.contains(reverse) {
            return true
        }
    }
    return false
}

- Tyler March 04, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

I used a custom hash table that would return false if the hash of a sorted string already existed in the hash table.

+(void)test {

    NSLog(@"Anagrams in array?: %hhd", [self anagramsInArray:@[@"cat", @"cta", @"dog"]]);
}

+(BOOL)anagramsInArray:(NSArray*)array {
    
    if (array.count < 1 || array == nil) {
        return false;
    }
    
    HashTable *hashTable = [HashTable new];
    
    for (id possibleString in array) {
        
        if ([possibleString isKindOfClass:[NSString class]]) {
            
            NSString *str = (NSString*)possibleString;
            if (![hashTable tryAddingUniqueValue:[str sortAscending]  ForKey:[str sortAscending]]) {
                return true;
            }
        }
    }
    
    return false;
}

+(NSArray*)stringToArray:(NSString*)string {
    
    NSMutableArray *mutableStringArray = [NSMutableArray new];
    
    for (int i = 0; i < [string length]; i++ ) {
        
        [mutableStringArray addObject:[NSString stringWithFormat:@"%c",[string characterAtIndex:i]]];
        
    }
    
    return mutableStringArray.copy;
    
        
}

- David.norman.w May 15, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

This is about as small as I could crunch this. Other answers along the way allude to portions of the solution here.

/**
 *  @brief Determine if two words are anagrams of each other.
 *  @discussion Runtime O( 2n )
 *
 *  @param word1 The first word
 *  @param word2 The second word. Possibly an anagram.
 *
 *  @return YES if the two words are anagrams, NO otherwise.
 */
bool areAnagrams(NSString *word1, NSString *word2)
{
    if (word1.length != word2.length || word1.length == 0 || word2.length == 0) {
        return NO;
    }
    
    const int size = 128;
    NSInteger len = [word1 length];
    NSInteger counter1[size];
    NSInteger counter2[size];
    NSInteger i;

    //This only shows values in LLDB if the arrays are statically sized during compilation.
    // For performance, these arrays should be initialized in their own for loop; stepping
    //  through each array index.
    memset(counter1, 0, sizeof(counter1));
    memset(counter2, 0, sizeof(counter2));

    for (i = 0; i < len; i++) {
        counter1[[word1 characterAtIndex:i]]++;
        counter2[[word2 characterAtIndex:i]]++;
    }
    
    for (i = 0; i < size; i++) {
        if (counter1[i] != counter2[i]) {
            return FALSE;
        }
    }
    return YES;
}

- Martin Stoufer June 07, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Using hash table:
You can loop on all words
for each word loop on its characters one by one as substring and sum their hashValue.
Once you have the hash value of all characters of the word, check if they are exist in the hash table, if YES, then we found a palindrome (there should be a dictionary to say its anagram), if NO, add this hash value to the hash table
This has linear space and time complexity of N characters of all words.

- Ahmed January 18, 2017 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

Below is the code that runs in O(n) written in Python. Running : ideone.com/4VksgA

from collections import Counter  

strings = [['bag', 'bat', 'tab'], ["gab", "bat", "laf"]] 

def twoAnagrams(strings):
    frequencies = set([])
    present = False
    for str in strings:
        freq = frozenset(Counter(str).items())
        if freq in frequencies:
            present = True
            break
        else:
            frequencies.add(freq) 
    print ("TRUE" if present else "FALSE")

for s in strings:
    twoAnagrams(s)

- Danstahr April 23, 2014 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Yes the solution looks good. But what is the hidden time complexity of these operations like "frozenset(Counter(str).items())" and "freq in frequencies". Especially the worst case time complexity? I guess freq is an unordered set so the time complexity is generally more than comparing two ordered sets.

- prd April 24, 2014 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

For a single word W, we need

* O(|W|) for counting the letters
* At most O(|W|) for converting it into set (perhaps not needed in other languages, in Python, we can't hash a dictionary)
* O(|W|) on average for looking it up in the set - I think it's safe to assume that we've got a sane implementation of hashtable

Note that set('a', 'b', 'c') is by design equal to set('c', 'b', 'a') and so it holds for the hash codes, which is the only thing that interests us. Internally, frozenset doesn't sort the items anyhow.

For all words, it just sums up to the size of the input.

- Dan.Stahr April 25, 2014 | Flag


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