I recently took a quiz asking me to determine if elements in an array were anagrams. I completed an implementation, but upon running their tests, I only passed 1 of 5 test cases. The problem is, they wouldn't allow me to see what the tests were, so I'm really unsure about what I failed on. I've recreated my answer below, which basically multiplies the letters in a word and adds this number to an array. It then compares the numbers in one array to the numbers in the other, and prints true if they are the same. I'm basically asking what are some scenarios in which this would fail, and how would I modify this code to account for these cases?
public class anagramFinder {
public static void main (String[] args){
String[] listOne = new String[5];
listOne[0] = "hello";
listOne[1] = "lemon";
listOne[2] = "cheese";
listOne[3] = "man";
listOne[4] = "touch";
String[] listTwo = new String[5];
listTwo[0] = "olleh";
listTwo[1] = "melon";
listTwo[2] = "house";
listTwo[3] = "namer";
listTwo[4] = "tou";
isAnagram(listOne,listTwo);
}
public static void isAnagram(String[] firstWords, String[] secondWords){
int firstTotal = 1;
int secondTotal = 1;
int[] theFirstInts = new int[firstWords.length];
int[] theSecondInts = new int[secondWords.length];
for(int i = 0;i<firstWords.length;i++){
for(int j = 0;j<firstWords[i].length();j++){
firstTotal = firstTotal * firstWords[i].charAt(j);
}
theFirstInts[i] = firstTotal;
firstTotal = 1;
}
for(int i = 0;i<secondWords.length;i++){
for(int j = 0;j<secondWords[i].length();j++){
secondTotal = secondTotal * secondWords[i].charAt(j);
}
theSecondInts[i] = secondTotal;
secondTotal = 1;
}
for(int i=0;i<minimum(theFirstInts.length,theSecondInts.length);i++){
if(theFirstInts[i] == theSecondInts[i]){
System.out.println("True");
} else {
System.out.println("False");
}
}
}
public static int minimum(int number,int otherNumber){
if(number<otherNumber){
return number;
} else {
return otherNumber;
}
}
}
In my above example that I run in the main method, this prints True True False False False, which is correct
Copying my answer from a similar question.
Here's a simple fast O(n) solution without using sorting or multiple loops or hash maps. We increment the count of each character in the first array and decrement the count of each character in the second array. If the resulting counts array is full of zeros, the strings are anagrams. Can be expanded to include other characters by increasing the size of the counts array.
class AnagramsFaster{
private static boolean compare(String a, String b){
char[] aArr = a.toLowerCase().toCharArray(), bArr = b.toLowerCase().toCharArray();
if (aArr.length != bArr.length)
return false;
int[] counts = new int[26]; // An array to hold the number of occurrences of each character
for (int i = 0; i < aArr.length; i++){
counts[aArr[i]-97]++; // Increment the count of the character at i
counts[bArr[i]-97]--; // Decrement the count of the character at i
}
// If the strings are anagrams, the counts array will be full of zeros
for (int i = 0; i<26; i++)
if (counts[i] != 0)
return false;
return true;
}
public static void main(String[] args){
System.out.println(compare(args[0], args[1]));
}
}
The idea of multiplying ASCII codes isn't bad, but not perfect. It would need a deep analysis to show that two different words could have the same products, with the given range of 'a' to 'z', and within reasonable length.
One conventional approach would be to create a Map for counting the letters, and compare the Maps.
Another one would sort the letters and compare the sorted strings.
A third one would iterate over the letters of the first word, try to locate the letter in the second word, and reduce the second word by that letter.
I can't think of a fourth way, but I'm almost certain there is one ;-)
Later
Well, here's a fourth way: assign 26 prime numbers to 'a' to 'z' and (using BigInteger) multiply the primes according to the letters of a word. Anagrams produce identical products.
Related
Lets say I have String word = "hello12".
I need to have all possible combinations of special characters instead of numbers (characters I get when use shift+number). So, the result I want to get is hello12, hello!2, hello1#, hello!#.
What I did is created switch with all cases (1 = '!', 2 = '#'...) but I can't get how to code all the combinations. All I could code is change all the numbers with special symbols (code is below)
char[] passwordInCharArray;
for(int i=0; i<passwordList.length; i++){
for(int j = 0; j<passwordList[i].length(); j++){
if(Character.isDigit((passwordList[i].charAt(j)))){
passwordInCharArray = passwordList[i].toCharArray();
passwordInCharArray[j] = getSpecialSymbol(passwordList[i].charAt(j));
passwordList[i]=String.valueOf(passwordInCharArray);
}
}
}
Theory
Combinatory is often easier to express with recursive methods (methods that call themselves).
I think that the algorithm is more understandable with an example so let's take String word = hello12.
We will iterate on each character until a digit is found. The first one is 1. At this point, we can imagine the word been split in two by a virtual cursor:
hello is on the left side. We know that it won't change.
12 is on the right side. Each character is likely to be a digit and thus to change.
To retrieve all the possible combinations, we want to:
Keep the first part of the word
Compute all the possible combinations of the second part of the word
Append each of these combinations to the first part of the word
The following tree represents what we want to compute (the root is the first part of the word, each branch represent a combination)
hello
├───1
│ ├───2 (-> hello12)
│ └───# (-> hello1#)
└───!
├───2 (-> hello!2)
└───# (-> hello!#)
You want to write an algorithm that gathers all the branches of this tree.
Java Code
/!\ I advise you to try to implement what I described above before taking a look at the code: that's how we improve ourselves!
Here is the corresponding Java code:
public static void main(String[] args) {
Set<String> combinations = combinate("hello12");
combinations.forEach(System.out::println);
}
public static Set<String> combinate(String word) {
// Will hold all the combinations of word
Set<String> combinations = new HashSet<String>();
// The word is a combination (could be ignored if empty, though)
combinations.add(word);
// Iterate on each word's characters
for (int i = 0; i < word.toCharArray().length; i++) {
char character = word.toCharArray()[i];
// If the character should be replaced...
if (Character.isDigit(character)) {
// ... we split the word in two at the character's position & pay attention not be exceed word's length
String firstWordPart = word.substring(0, i);
boolean isWordEnd = i + 1 >= word.length();
String secondWordPart = isWordEnd ? "" : word.substring(i + 1);
// Here is the trick: we compute all combinations of the second word part...
Set<String> allCombinationsOfSecondPart = combinate(secondWordPart);
// ... and we append each of them to the first word part one by one
for (String string : allCombinationsOfSecondPart) {
String combination = firstWordPart + getSpecialSymbol(character) + string;
combinations.add(combination);
}
}
}
return combinations;
}
Please leave a comment if you want me to explain the algorithm further.
Building on the code from: Generate All Possible Combinations - Java, I've come up with this implementation that does what you need. It will find the index of all digits in your string and then generate all possibilities in which they can be replaced with the special characters.
import java.util.*;
public class Comb {
public static List<String> combinations(String pass) {
String replace = ")!##$%^&*(";
char[] password = pass.toCharArray();
List<Integer> index = new ArrayList<Integer>();
List<String> results = new ArrayList<String>();
results.add(pass);
//find all digits
for (int i = 0; i < password.length; i++) {
if (Character.isDigit(password[i])) {
index.add(i);
}
}
//generate combinations
int N = (int) Math.pow(2d, Double.valueOf(index.size()));
for (int i = 1; i < N; i++) {
String code = Integer.toBinaryString(N | i).substring(1);
char[] p = Arrays.copyOf(password, password.length);
//replace the digits with special chars
for (int j = 0; j < index.size(); j++) {
if (code.charAt(j) == '1') {
p[index.get(j)] = replace.charAt(p[index.get(j)] - '0');
}
}
results.add(String.valueOf(p));
}
return results;
}
public static void main(String... args) {
System.out.println(combinations("hello12"));
}
}
I had to do a test today for an interview and the problem was obtaining the lexicographically smallest and largest substring (in other words, sort by name).
Link - Complete the function SmallestAndLargestSubstring, which takes a string S consisting of lowercase English letters (a-z) as its argument and returns lexicographically smallest and largest substrings which start with a vowel and end with a consonant.
My algorithm passed the basic test cases but failed most of the others. It's not the most efficient code, but it was the fastest to write.
static String[] SmallestAndLargestSubstring(String s) {
ArrayList<Character> vowelList = new ArrayList<Character>();
vowelList.add('a');
vowelList.add('e');
vowelList.add('i');
vowelList.add('o');
vowelList.add('u');
ArrayList<Character> consonantList = new ArrayList<Character>();
for (char c='a'; c<='z'; c++) {
if (!vowelList.contains(c))
consonantList.add(c);
}
ArrayList<String> substringList = new ArrayList<String>();
for (int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (vowelList.contains(c)) {
String substring = "";
substring+=c;
for (int j=i+1; j<s.length(); j++) {
char c2 = s.charAt(j);
substring+=c2;
if (consonantList.contains(c2)) {
substringList.add(substring);
}
}
}
}
Collections.sort(substringList);
String[] outputAdapter = new String[2];
outputAdapter[0]=substringList.get(0);
outputAdapter[1]=substringList.get(substringList.size()-1);
return outputAdapter;
}
Anyway, I wanted to figure out where I went wrong, so I reversed engineered the test cases to figure out what was the input being passed in, and hopefully I would be able to figure out what was wrong with my algorithm.
Here's what I uncovered, and these are my answers (which are wrong according to the test cases).
Input
String s = "azizezozuzawwwwwwwwwuzzzzzzzzabbbbbbbaaaabbbboiz"
My answer
smallest = "aaaab";
largest = "uzzzzzzzzabbbbbbbaaaabbbboiz";
But for the life of me, I can't figure out where my mistake is. Here's my full list of substrings, sorted from the smallest to the largest. Link to sorted results
Been racking my brains for the last 3 hours. I'd be grateful if anyone can figure out where my mistake was.
Edit: Here are 3 more test cases. My answers match these test case answers.
string = "aba"; smallest = "ab"; largest = "ab";
string = "aab"; smallest = "aab"; largest = "ab";
string = "abababababbaaaaaaaaaaaaaaz"; smallest = "aaaaaaaaaaaaaaz"; largest = "az";
/*
It is the Basic code to Obtain Substring which start with Vowel and End up with Consonant. It is going to print on the Basis of Name Comparable, The first and the Last Substring in the List.Similarly we can achieve on the basis of length, the firt and last Substring using different comparator function.
*/
public class StringSubsequencesStartVowelEndConsonant {
static List<String> subsequence = new LinkedList<>();
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter the String:\n");
String string = in.next();
findSubstring(string);
}
private static void findSubstring(String string) {
for(int i=0;i<string.length();i++){
if(isVowel(string.charAt(i))){
for(int j=string.length()-1;j>=i;j--){
if(isConsonant(string.charAt(j))){
String subString = string.substring(i,j+1);
subsequence.add(subString);
}
}
}
}
Collections.sort(subsequence);
for(String str : subsequence){
System.out.print(str+" ");
}
System.out.println();
System.out.println(subsequence.get(0));
System.out.println(subsequence.get(subsequence.size()-1));
}
private static boolean isConsonant(char chars) {
return !(chars=='a'|| chars=='e'||chars=='i'||chars=='o'||chars=='u');
}
private static boolean isVowel(char chars) {
return (chars=='a'|| chars=='e'||chars=='i'||chars=='o'||chars=='u');
}
}
Basically i am trying to create an algorithm that will test whether a given string is a cover string for a list of strings. A string is a cover string if it contains the characters for every string in the list in a way that maintains the left to right order of the listed strings. For example, for the two strings "cat" and "dog", "cadhpotg" would be a cover string, but "ctadhpog" would not be one.
I have created an algorithm however it is producing the output true when the output should be false, as the given string is a cover String for Strings list1 and list2, but not for list3.
Any help into why this algorithm is producing the wrong output would be highly appreciated.
public class StringProcessing2 {
//ArrayList created and 3 fields added.
public static ArrayList<String> stringList = new ArrayList<>();
public static String list1 = "phillip";
public static String list2 = "micky";
public static String list3 = "fad";
//Algorithm to check whether given String is a cover string.
public static boolean isCover(String coverString){
int matchedWords = 0;
stringList.add(list1);
stringList.add(list2);
stringList.add(list3);
//for-loops to iterate through each character of every word in stringList to test whether they appear in
//coverString in left to right order.
for(int i = 0; i < stringList.size(); i++){
int countLetters = 1;
for(int n = 0; n < (stringList.get(i).length())-1; n++){
if(coverString.indexOf(stringList.get(i).charAt(n)) <= (coverString.indexOf((stringList.get(i).charAt(n+1)),
coverString.indexOf((stringList.get(i).charAt(n)))))){
countLetters++;
if(countLetters == stringList.get(i).length()){
matchedWords++;
}
}
}
}
if(matchedWords == stringList.size()){
return true;
}
else
return false;
}
public static void main(String[] args) {
System.out.println(isCover("phillmickyp"));
}
}
Probably the easiest way to go about this is to break down the problem into parts. Have every function do the least possible work while still getting something done towards the overall goal.
To accomplish this, I'd recommend creating a helper method that takes two Strings and returns a boolean, checking if one String is the cover of another.
boolean isCover(String s, String cover)
{
int i = 0;
for(char c : s.toCharArray())
if((i = cover.indexOf(c, i)) == -1)
return false;
return true;
}
Then once you have something that can correctly tell you if it's a valid cover String or not, it becomes much simpler to check if one String is a valid cover for multiple Strings
boolean isCover(List<String> strings, String cover)
{
for(String s : strings)
if(!isCover(s, cover))
return false;
return true;
}
I need a String array with the following attributes:
4 digits numbers
No repeating digits ("1214" is invalid)
No 0's
Is there an easier way to do this than manually type it? Like:
String[] s = {"1234","1235",1236",1237",1238",1239","1243","1245"};
Sorry for my English!
The following code will generate an array with your specifications.
public class Test {
public static void main(String[] args) {
List<String> result = new ArrayList<>();
Set<Character> set = new HashSet<>();
for (int i = 1234; i <= 9876; i++) {
set.clear();
String iAsString = Integer.toString(i);
char[] chars = iAsString.toCharArray();
boolean valid = true;
for (char c : chars) {
if (c == '0' || !set.add(c)) {
valid = false;
break;
}
}
if (valid) {
result.add(iAsString);
}
}
String[] yourStringArray = result.toArray(new String[result.size()]);
System.out.println(Arrays.toString(yourStringArray));
}
}
****edit****
Just saw that it is in Java. So use this function: String.valueOf(number) to convert integer to string if none of the digits are repeats in the loop.
Not sure what language you are doing but I am assuming no repeats not replies.
So what you can do is have a loop from 0 to 9999 and then run through all the numbers while checking if each digit has repeats if so discard number (do not store it into array).
You can convert integers to strings in many languages in their function so you can do that then store it into array.
Good luck.
Hope this helped (fastest solution from my head...there could be more efficient ones)
Try this method for creating Random number with your structure :
ArrayList<Integer> rawNumbers = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9));
public String createRandomNumberSring()
{
String result = "";
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.addAll(rawNumbers);
for(int i = 0; i < 4; i++)
{
int index = (int)(Math.random() * (numbers.size() + 1));
result += numbers.get(index).toString();
numbers.remove(index);
}
return result;
}
Having problems trying to show every combination of a character of array without repeating letters.
public static String[] getAllLists(String[] elements, int lengthOfList)
{
//initialize our returned list with the number of elements calculated above
String[] allLists = new String[(int)Math.pow(elements.length, lengthOfList)];
//lists of length 1 are just the original elements
if(lengthOfList == 1) return elements;
else
{
//the recursion--get all lists of length 3, length 2, all the way up to 1
String[] allSublists = getAllLists(elements, lengthOfList - 1);
//append the sublists to each element
int arrayIndex = 0;
for(int i = 0; i < elements.length; i++)
{
for(int j = 0; j < allSublists.length; j++)
{
//add the newly appended combination to the list
allLists[arrayIndex] = elements[i] + allSublists[j];
arrayIndex++;
}
}
return allLists;
}
}
The above code works perfect but use's each letter more than once which cant be done in this case.
And i am stuck how to do this now.
Here's an example implementation. Essentially it takes a String and iterates over every character, putting that character at the front. It then recurses on the remaining characters. That structure removes your issue of repeated letters, because the input to the recursion has removed the character you've already used.
I also stored results in a set to remove semantic equivalences. The input 'aab' can switch char 0 and char 1 but still be 'aab.' I used a TreeSet to preserve ordering for easier verification of the output, but HashSet would be faster.
public static Set<String> permute(String chars)
{
// Use sets to eliminate semantic duplicates (aab is still aab even if you switch the two 'a's)
// Switch to HashSet for better performance
Set<String> set = new TreeSet<String>();
// Termination condition: only 1 permutation for a string of length 1
if (chars.length() == 1)
{
set.add(chars);
}
else
{
// Give each character a chance to be the first in the permuted string
for (int i=0; i<chars.length(); i++)
{
// Remove the character at index i from the string
String pre = chars.substring(0, i);
String post = chars.substring(i+1);
String remaining = pre+post;
// Recurse to find all the permutations of the remaining chars
for (String permutation : permute(remaining))
{
// Concatenate the first character with the permutations of the remaining chars
set.add(chars.charAt(i) + permutation);
}
}
}
return set;
}
Example run:
public static void main(String[] args)
{
for (String s : CharPermuter.permute("abca"))
{
System.out.println(s);
}
}
Generates:
aabc
aacb
abac
abca
acab
acba
baac
baca
bcaa
caab
caba
cbaa