Amazon Interview Question
Software Engineer / DevelopersCountry: United States
Interview Type: Phone Interview
I also had a similar idea looking at this.
But the getkey function returns the key by taking sum of int. I think we could have 2 scenario where two diff words which are not permutaiton/anagrams returns the same key.
may be taking the product by assigning each character a unique prime number (non-negative) would solve the issue.
But both these approaches may lead to overflow, so we might use big integer sort of data structure to resolve this issue.
Thoughts or i am missing something.
This implementation would add duplicates to the set .
For example , the output would be [ ( abc,cab ) ( ba,ba ) ( b ) ]
To remove duplicates like "ba" in the example above I think we can preprocess the data or while checking for "isPermutation" instead of comparing with just one element , have a "for loop" that iterates over the entire vector .
#include <iostream>
#include <string>
#include <vector>
using namespace std ;
typedef vector<string> vectorOfStrings ;
vector<vectorOfStrings> listOfSetsOfPermutations ;
// Utility function to check if two strings
// are permutations of each other.
// Assumes an ASCII character set ( 0 - 255 )
bool
isPermutation( string str1 , string str2 ) {
if( str1.length() != str2.length() ) {
return false ;
}
// trackCharacters maintains the count of each
// character's occurence in str1 . We store it
// in the index represented by the ASCII value
// of the character .
int trackCharacters[ 256 ] ;
int characterValue = 0 ;
// Initialize the array to avoid
// undefined behaviour .
for( int i = 0 ; i < 256 ; i++ ) {
trackCharacters[i] = 0 ;
}
for( int i = 0 ; i < str1.length() ; i++ ) {
characterValue = str1.at(i) ;
trackCharacters[characterValue]++;
}
// When parsing the 2nd string , for each
// character that is common between the two
// strings , we reduce the count of character
// occurences . If at any point the count for
// a character goes below 0 , str2 is not a
// permutation of str1 .
for( int i = 0 ; i < str2.length() ; i++ ) {
characterValue = str2.at(i) ;
trackCharacters[characterValue] --;
if( trackCharacters[characterValue] < 0 ) {
return false ;
}
}
return true ;
}
vector<vectorOfStrings>
computeListOfSetsOfPermutations( vectorOfStrings inputData , int index ) {
bool permutation = false ;
if( index == 0 ) {
vectorOfStrings set = vectorOfStrings() ;
set.push_back( inputData[index] ) ;
listOfSetsOfPermutations.push_back( set ) ;
} else {
for( int i = 0 ; i < listOfSetsOfPermutations.size() ; i++ ) {
vectorOfStrings set = listOfSetsOfPermutations[i] ;
if( isPermutation( set[0],inputData[index] ) ) {
listOfSetsOfPermutations[i].push_back( inputData[index] ) ;
return listOfSetsOfPermutations ;
}
}
vectorOfStrings newSet = vectorOfStrings() ;
newSet.push_back( inputData[index] ) ;
listOfSetsOfPermutations.push_back( newSet ) ;
return listOfSetsOfPermutations ;
}
for( int i = 1 ; i < inputData.size() ; i++ ) {
listOfSetsOfPermutations = computeListOfSetsOfPermutations( inputData , i );
}
return listOfSetsOfPermutations ;
}
// Driver code to test
int
main() {
vectorOfStrings inputData = vectorOfStrings() ;
inputData.push_back("abc") ;
inputData.push_back("cab") ;
inputData.push_back("ba") ;
inputData.push_back("b") ;
inputData.push_back("ba") ;
listOfSetsOfPermutations = computeListOfSetsOfPermutations( inputData,0 ) ;
cout << "[ " ;
for( int i = 0 ; i < listOfSetsOfPermutations.size() ; i++ ) {
vectorOfStrings permutationSubset = listOfSetsOfPermutations[i] ;
cout << "( " ;
for( int j = 0 ; j < permutationSubset.size() ; j++ ) {
cout << permutationSubset[j] << "," ;
}
cout << " ) " ;
}
cout << " ] " << "\n" ;
return 1 ;
}
the following code handles cases when more then one permutation of a string is present and also deals with duplicate case
public class CheckPermutation {
static String[] words= {"abc","cab","ba", "b", "ba","bca","ab","cba"};
public static boolean checkIfPermutation(String s1,String s2)
{
if(s1.length()!=s2.length())
return false;
char[] lett= s1.toCharArray();
for(char c:lett)
{
String s= Character.toString(c);
if(!s2.contains(s))
return false;
}
return true;
}
public static void printPermutations()
{
boolean match=false;
int[] id=new int[words.length];
for(int k=0;k<id.length;k++)
{
id[k]=-1;
}
for(int i=0;i<words.length-1;i++)
{
if(id[i]!=1){
match=false;
System.out.print(words[i]+" ");
for(int j=i+1;j<words.length;j++){
match=checkIfPermutation(words[i],words[j]);
if(match==true && words[i]!=words[j]&&id[j]==-1)
{
id[i]=1;
id[j]=1;
System.out.print(words[j]+" ");
continue;
}
if(match==true && words[i]==words[j])
{
id[i]=1;
id[j]=1;
//System.out.println(words[i]);
continue;
}
}
System.out.println();
}
}
}
public static void main(String[] args) {
printPermutations();
}
}
There is a small problem i the code, in case the alphabets are duplicated it wont work. e.g. :- "abcc","cabb","ba", "b", "ba","bca","ab","cba"
thanks for pointing it out. I have added another function getCount which takes care of cases specified by you.
/*Given a list of strings, write an alogirthm that will return a list of sets of
permutations.
*
* sample input: [abc, cab, ba, b, ba]
* sample output: [{abc, cab}, {ba}, {b}]
*/
import java.util.*;
public class CheckForPermutation {
static String[] words= {"abcc","cabb","ba", "b", "ba","bca","ab","cba"};
public static boolean checkIfPermutation(String s1,String s2)
{
if(s1.length()!=s2.length())
return false;
char[] lett= s1.toCharArray();
for(char c:lett)
{
String s= Character.toString(c);
if(!s2.contains(s))
return false;
}
return true;
}
public static void printPermutations()
{
boolean match=false;
boolean countEqual=false;
int[] id=new int[words.length];
for(int k=0;k<id.length;k++)
{
id[k]=-1;
}
for(int i=0;i<words.length-1;i++)
{
if(id[i]!=1){
match=false;
System.out.print(words[i]+" ");
for(int j=i+1;j<words.length;j++){
match=checkIfPermutation(words[i],words[j]);
countEqual= getCount(words[i],words[j]);
if(match==true && words[i]!=words[j]&&id[j]==-1 && countEqual==true)
{
id[i]=1;
id[j]=1;
System.out.print(words[j]+" ");
continue;
}
if(match==true && words[i]==words[j])
{
id[i]=1;
id[j]=1;
continue;
}
}
System.out.println();
}
}
}
public static boolean getCount(String a,String b)
{
if(a.length()!=b.length())
return false;
Map<Character,Integer> ha = new HashMap<Character,Integer>();
Map<Character,Integer> hb = new HashMap<Character,Integer>();
for(int i=0;i<a.length()-1;i++)
{
int count=0;
for(int j=i+1;j<a.length();j++)
{
if(!ha.containsKey(a.charAt(i)))
{
if(a.charAt(i)==a.charAt(j))
count++;
}
}
ha.put(a.charAt(i), count);
}
for(int i=0;i<b.length()-1;i++)
{
int count=0;
for(int j=i+1;j<a.length();j++)
{
if(!hb.containsKey(b.charAt(i)))
{
if(b.charAt(i)==b.charAt(j))
count++;
}
}
hb.put(b.charAt(i), count);
}
Set sa= ha.entrySet();
Set sb= hb.entrySet();
Iterator ia= sa.iterator();
Iterator ib = sb.iterator();
while(ia.hasNext())
{
Map.Entry pairs= (Map.Entry)ia.next();
Character ch= new Character((char) pairs.getKey());
Integer va= new Integer((int)pairs.getValue());
if(hb.containsKey(ch))
{
int vb= new Integer((int)hb.get(ch));
if(va!=vb)
{
return false;
}
}
else
return false;
}
return true;
}
public static void main(String[] args) {
printPermutations();
}
}
int main()
{
int i, len, j, temp, k = 0, found = 0;
char *in;
int calPrime[10] = {1, 1, 1, 1, 1, 1, 1, 1};
int pind[10];
char prime[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
std::string input[] = {"abc", "cab", "ba", "b", "ba", "cba", "ab", "b"};
for(i=0; i<8; i++)
{
in = (char *)input[i].c_str();
len = strlen(in);
for(j = 0; j<len; j++)
{
calPrime[i] *= prime[in[j] - 'a'];
}
printf("prime: %d\n", calPrime[i]);
}
for(i=0; i<8; i++)
{
for(int n=0; n<k; n++)
{
if(i == pind[n])
{
found = 1;
break;
}
}
if(found == 1)
{
found = 0;
continue;
}
temp = calPrime[i];
printf("pairs: (%s ", input[i].c_str());
for(j = i+1; j<8; j++)
{
if( temp == calPrime[j]) {
pind[k++] = j;
printf(", %s", input[j].c_str());
}
}
printf(")\n");
}
return 0;
}
Insert each word in trie.
While inserting use count [26] to sort the word.
each time word is inserted at the end of trie, add the index of word as in original list,
Now traverse trie and output all words and return the index from trie.
suppose u have to add "dcb"
the corresponding count array will be
count['b']=1;
count['c']=1;
count['d']=1;
all other 23 count chars will be 0
now on reading from top u will get 'bcd'
insert this in trie
and add the index of this word 'dcb' from the input array to the end of trie.
Affter all words are inserted. Traverse the trie.
Each termination of word will get u some indexes in orginal array(all these words are anagram of each other).
Now insert all these words in Set(to remove duplicates), and remove them back.
///
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CareerCup
{
class Program
{
static void Main(string[] args)
{
string[] inputs = { "abc", "cab", "ba", "b", "ba", "ba", "acb"};
var setMap = new Dictionary<string, HashSet<string>>();
foreach (var item in inputs)
{
var sortedCharItem = SortCharacters(item);
HashSet<string> set;
if (!setMap.TryGetValue(sortedCharItem, out set))
{
set = new HashSet<string>();
setMap.Add(sortedCharItem, set);
}
set.Add(item);
}
foreach (var set in setMap)
{
foreach (var item in set.Value)
{
Console.Write(item + " ");
}
Console.WriteLine();
}
}
static string SortCharacters(string input)
{
var chars = input.ToCharArray();
Array.Sort<char>(chars);
return new string(chars);
}
}
}
\\\
int strCompare(char a[], char b[])
{
int len = strlen(a);
if(len != strlen(b))
return 0;
for(int i=0; i<len; i++)
{
if(a[i]-b[i] != 0)
return 0;
}
return 1;
}
int isPermutation(char a[], char b[])
{
int len = strlen(a);
int i, j;
if(len != strlen(b))
return 0;
else
{
for(i=0; i<len; i++)
{
for(j=0; j<len; j++)
{
if(a[i]-b[j] == 0)
break;
}
if(j == len)
return 0;
}
return 1;
}
}
int main(void)
{
/************************************/
char *str[]={"abc", "cba", "ba", "b", "ba"};
int sn[5] = {0};//store if this string has been marked as printed
int i = 0, j = 0;
//method 1
for(i = 0; i < 5; i++)
{
if(sn[i] == 1)
continue;
//if(sn[i] == 0)
printf("%s\n\r", str[i]);
for(j=i+1; j<5 && !sn[j]; j++)
{
if(strCompare(str[i], str[j]))
{
sn[j] = 1;
}else if(isPermutation(str[i],str[j]))
{
sn[j] = 1;
printf("%s\n\r", str[j]);
}
}
}
//build list which include *str
return 0;
}
I blv ur isPermutation() function is not working correctly.
Check it with a[] = "aaa" , b[]= "bac" .
It'll always find all chars 'a' in b[] so wud return 1 .
Following C++ solution can be used : (Ref: stack overflow)
int main (int argc, char * const argv[]) {
string s = "sarp";
bool used [4];
permute(0, "", used, s);
}
void permute(int level, string permuted, bool used [], string &original) {
int length = original.length();
if(level == length) { // permutation complete, display
cout << permuted << endl;
} else {
for(int i=0; i<length; i++) { // try to add an unused character
if(!used[i]) {
used[i] = true;
permute(level+1, original[i] + permuted, used, original); // find the permutations starting with this string
used[i] = false;
}
}
}
import java.io.*;
import java.util.Arrays;
public class strpermut {
public static void main(String[] args) throws IOException {
String s,sor1,sor2;
int t,i,j;
char []arr1 = new char[30];
char []arr2 = new char[30];
String s2[]= new String[30];
System.out.print("input");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
s= br.readLine();
s2=s.split(" ");
int len=s2.length;
for(i=0;i<len-1;i++){
arr1=s2[i].toCharArray();
Arrays.sort(arr1);
sor1 = String.valueOf(arr1);
for(j=i+1;j<len;j++){
arr2=s2[j].toCharArray();
Arrays.sort(arr2);
sor2 = String.valueOf(arr2);
if(sor1.compareTo(sor2)==0){
System.out.println("pairs "+s2[i]+" "+s2[j]);
}
}
}
}
}
- hotcoder October 16, 2012