Anagram Checking Logical Error - Cant seem to find the error - java

public class AnagramUnoptimized {
public static void main(String[] args) {
String a = "good";
String b = "ogod";
boolean isAnagram = false;
String c = a.toLowerCase();
String d = b.toLowerCase();
if(c.length()==d.length()) {
boolean [] Visited = new boolean[a.length()];
for (int i = 0; i < c.length(); i++) {
isAnagram = false;
for (int j = 0; j < d.length(); j++) {
if (c.charAt(i) == d.charAt(j) && Visited[j]==false) {
isAnagram = true;
Visited[j] = true;
}
}
if (isAnagram == false) {
break;
}
}
}
if(isAnagram==true){
System.out.println("The given Strings are Anagrams");
}
else{
System.out.println("The given Strings are not Anagrams");
}
}
}
I used a Visited boolean array to check for repeated items but its now showing "Not anagram" for all inputs....
Can you tell me why its showing "Not anagram" if the strings have repeating elements??

The problem with your code is you are continuing with the loop even when visited[j] is changed to true whereas you need to break the inner loop at this point. Do it as follows:
for (int j = 0; j < d.length(); j++) {
if (c.charAt(i) == d.charAt(j) && visited[j] == false) {
isAnagram = true;
visited[j] = true;
break;
}
}
The output after this change:
The given Strings are Anagrams
A better way to do it would be as follows:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String a = "good";
String b = "ogod";
char[] first = a.toLowerCase().toCharArray();
char[] second = b.toLowerCase().toCharArray();
Arrays.sort(first);
Arrays.sort(second);
boolean isAnagram = Arrays.equals(first, second);
if (isAnagram == true) {
System.out.println("The given Strings are Anagrams");
} else {
System.out.println("The given Strings are not Anagrams");
}
}
}
Output:
The given Strings are Anagrams

In your code you should break the inner for loop when the
condition "if (c.charAt(i) == d.charAt(j) && Visited[j]==false)"
has been meet. Because it is still looping through the second stiring and if it will meet the same char one angain it will change the value of Visited[] to true two times, leading to an error. It this example this is the case witch char 'o'. Adding " break; " at the end of the if statement should fix the problem.

Related

are two anagram or not? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
My question is that in this code, initially we have taken boolean isAnagram false, and then set the condition, but we are getting wrong result. As it is clearly understood that they are not anagram but code output is 'anagram' .
package strings;
public class Anagrams {
public static void main(String[] args) {
String a = "aab";
String b = "abc";
boolean isAnagram = false;
int al[] = new int[256];
int bl[] = new int[256];
for(char c:a.toCharArray()) {
int index = (int)c;
al[index]++;
}
for(char c:b.toCharArray()) {
int index = (int)c;
bl[index]++;
}
for(int i = 0; i<256; i++) {
if(al[i] == bl[i]) {
isAnagram = true;
}
}
if(isAnagram) {
System.out.println("anagram");
}else {
System.out.println("not anagram");
}
}
}
}
I think sorting the string and then compare them is more simple.
public static void main(String[] args) {
String a = "aab";
String b = "abc";
char[] a1 = a.toLowerCase().toCharArray();
char[] b1 = b.toLowerCase().toCharArray();
Arrays.sort(a1);
Arrays.sort(b1);
boolean isAnagram = new String(a1).equals(new String(b1));
System.out.println(isAnagram ? "anagram" : "not anagram");
}
Okay.
The questioner wants his own algorithm to work.
The main bug is that it needs to find mismatches in the char set for two words being compared.
So you can declare a counter and while you iterate through char position in both words you increase the counter every time you find a mismatch between the number of some specific letter in the first and the second word.
At the end, if the counter > 0, this means the words have different sets of chars.
The working code:
class Ideone
{
// Online Java Compiler
// Use this editor to write, compile and run your Java code online
public static void main(String[] args) {
String a = "aab";
String b = "abb";
int mismatch = 0;
boolean isAnagram = true;
int al[] = new int[143859];
int bl[] = new int[143859];
for(char c:a.toCharArray()) {
int index = (int)c;
al[index]++;
}
for(char c:b.toCharArray()) {
int index = (int)c;
bl[index]++;
}
for(int i = 0; i<143859; i++) {
if(al[i] != bl[i]) {
mismatch++;
}
}
if (mismatch>0) isAnagram = false;
if(isAnagram) {
System.out.println("anagram");
}else {
System.out.println("not anagram");
}
}
}
Your code yields true if ONE char count matches. But it should only be true if ALL char counts match. Turn the logic around, start with true and set to false on the first mismatch. Change the line
boolean isAnagram = false;
to
boolean isAnagram = true;
and
if(al[i] == bl[i]) {
isAnagram = true;
}
to
if(al[i] != bl[i]) {
isAnagram = false;
break;
}
But sorting the strings is indeed the solution that is more readable and easier to understand.
The problem is the last for-loop:
for(int i = 0; i<256; i++) {
if(al[i] == bl[i]) {
isAnagram = true;
}
}
If only a single position in both arrays match, isAnagram is set to true. To fix the problem, We can inverse our perspective: Let us assume that the two Strings are anagrams at the start (boolean isAnagram = true;) and set the flag to false iff. the two arrays a and b differ on some index i. We can also break the loop on the first mismatch we find.
public static void main(String[] args) {
String a = "aab";
String b = "aac";
boolean isAnagram = true;
int al[] = new int[256];
int bl[] = new int[256];
for (char c : a.toCharArray()) {
int index = (int) c;
al[index]++;
}
for (char c : b.toCharArray()) {
int index = (int) c;
bl[index]++;
}
for (int i = 0; i < 256; i++) {
if (al[i] != bl[i]) {
isAnagram = false;
break;
}
}
if (isAnagram) {
System.out.println("anagram");
} else {
System.out.println("not anagram");
}
}
Ideone demo
Since chars in Java are encoded in unicode, it could occur that the int-value of a char is >= 256 (Ideone demo). To prevent this problem, we can use a Map<Integer, Integer> to keep track of the codepoint frequency:
public static boolean areAnagrams(String s, String t) {
Objects.requireNonNull(s, "Parameter \"s\" is null");
Objects.requireNonNull(t, "Parameter \"t\" is null");
return Objects.equals(s, t) ||
Objects.equals(getCodePointFrequency(s), getCodePointFrequency(t));
}
public static Map<Integer, Integer> getCodePointFrequency(String s) {
return s.codePoints()
.boxed()
.collect(Collectors.toMap(Function.identity(), c -> 1, Integer::sum));
}
Ideone demo
It should be mentioned that this solution has a worst-case time complexity of O(n log(n)) since an insert into a map only guarantees O(log(n)), not O(1). The average case, however, should be O(max(n)), with n being the length of the longer String of s and t.

Boundary Case conditions for String Anagrams

I trying to write one string Anagram program but stuck while checking the boundary conditions.
I know there are lots of ways and programs available on internet related to String Anagrams using single loops or using collections framework, but I need the solution for my code that how can I involve boundary cases for the code.
public class StringAnagram {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str = "abc";
String strAnagram = "cba";
boolean areAnagrams = ifAnagrams(str, strAnagram);
System.out.println(areAnagrams);
}
private static boolean ifAnagrams(String str, String strAnagram) {
// TODO Auto-generated method stub
int count = 0;
char[] a = strAnagram.toCharArray();
if (str.length() != strAnagram.length()) {
return false;
}
for (int i = 0; i < str.length(); i++) {
{
System.out.println("str.charAt(i) in outer loop :" + str.charAt(i));
for (int j = 0; j < strAnagram.length(); j++) {
if (str.charAt(i) == strAnagram.charAt(j)) {
System.out.println("str.charAt(i) : " + str.charAt(i));
System.out.println("strAnagram.charAt(j) : " + strAnagram.charAt(j));
count++;
}
}
}
System.out.println(count);
if (count == str.length()) {
return true;
}
}
return false;
}
}
Code is working fine if I am inputting the input likes -
"abc" or "abcd" where each char in string is occuring only one time, but it fails when input is like "aab" can be compared to "abc" and it will show strings are anagrams.
So, how this condition I can handle in my code. Please advice.
The problem with your solution is that it only checks if each character in the first string is present in the second string. There are 2 more conditions you need to consider:
If each character in the second string is also present in the first string
If character count for each character in the first and the second string matches
Your current solution will return True for input of ("aaa", "abc") while it should return False. Implementing the first condition I mentioned above will fix this problem.
After you implement the first condition, your solution will return True for input of ("abb", "aab") while it should return False. Implementing the second condition I mentioned above will fix this problem.
Here is a simple way to make this work:
Map<Character, Integer> charCount = new HashMap<Character, Integer>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (charCount.containsKey(c)) {
charCount.put(c, charCount.get(c)+1);
} else {
charCount.put(c, 1);
}
}
for (int i = 0; i < strAnagram.length(); i++) {
char c = strAnagram.charAt(i);
if (!charCount.containsKey(c)) return false;
if (charCount.get(c) == 0) return false;
charCount.put(c, charCount.get(c)-1);
}
for (char k : charCount.keySet()) {
if (charCount.get(k) != 0) return false;
}
return true;
Since there are no nested loops, the time complexity is O(n). Even though a Map is used, the space complexity is O(1), since it is guaranteed that the total number of keys will not exceed the number of all possible characters.
This solution is even better than sorting in terms of time and space complexity.
This may still be wildly inefficient. Again I apologize for initially overlooking your requirement that no collection frameworks could be included.
public class StringAnagram {
public static void main(String[] args) {
// TODO Auto-generated method stub
// String str = "abc";
// String strAnagram = "cba";
String str = "abcdd";
String strAnagram = "dccba";
boolean areAnagrams = ifAnagrams(str, strAnagram);
System.out.println(areAnagrams);
}
private static boolean ifAnagrams(String str, String strAnagram) {
int count = 0;
char[] a = strAnagram.toCharArray();
char[] b = str.toCharArray();
String alphaString = "abcdefghijklmnopqrstuvwxyz";
char[] alpha = alphaString.toCharArray();
System.out.println(a);
System.out.println(b);
System.out.println("");
if (str.length() != strAnagram.length()) {
return false;
}
for (int i=0; i < alpha.length; i++) {
int countA = 0;
int countB = 0;
for(int j = 0; j < a.length; j++){
if (a[j] == alpha[i]) {
countA++;
}
if (b[j] == alpha[i]) {
countB++;
}
}
if (countA != countB) {
return false;
}
}
return true;
}
}
This alternate solution makes use of a string that contains all the letters in the alphabet, and iterates through them to check if both strings have the same count of each letter. No frameworks this time :)

Recursion behaving in an unexpected manner with Java

I'm a student, and I've been working on the following challenge: find a substring (the needle) in a larger string (the haystack) without using the substring method, and using recursion. Recursion isn't my strong suit, but I have worked out the following:
public class Contains
{
public static void main(String[] args)
{
System.out.println(contains("Java programming", "ogr", false));
}
public static boolean contains(String haystack, String needle, boolean doesContain)
{
if(haystack.length() < needle.length())
{
return false;
}
else
{
for(int i = 0; i < needle.length(); i++)
{
if(haystack.charAt(i) != needle.charAt(i))
if((i + 1) == needle.length())
{
doesContain = false;
break;
}
else
break;
else
if((i + 1) == needle.length())
{
doesContain = true;
break;
}
else
continue;
}
char[] haystackChar = haystack.toCharArray();
char[] newCharArray = new char[(haystackChar.length - 1)];
for(int j = 1; j < haystackChar.length; j++)
{
newCharArray[j - 1] = haystackChar[j];
}
String newStr = new String(newCharArray);
if(doesContain == false)
contains(newStr, needle, doesContain);
}
return doesContain;
}
}
I realize this might not be the best or most elegant solution, but I am mostly just trying to get it to work. I've been running it in the Eclipse debugger, and everything is functioning as expected up until the call to if(doesContain == false) during the method call to contain where doesContain is set to true during the iteration of the for loop. The debugger is showing the value of doesContain to (correctly) be true, and it shows it skipping over the if statement, and exiting the else block. However, immediately after that, it jumps back up into the else block and only calls the recursive call to contain, instead of returning doesContain. Then, it continues to work recursively and subsequently fail and return false, because it's now searching through the rest of the string, where the "needle" is not located.
I know that StackOverflow is not a 'homework help' location per se, but I program for purposes other than school, and I'm quite perplexed as to why it's behaving this way. Does anyone know why it's doing this? Am I missing something here?
I took a look through your code and ran it in eclipse myself. A theory you will want to look into is how stacking works in recursion. Your program is finding true and then leaving the stack, but by that point it had reoccurred several times. It returned true, but then also went on to return all the false variables that were stored before it.
If you have any further questions please let me know.
EDIT
If you are really interested in getting into advanced recursion I highly recommend this video: Java Recursion
Hey, I didn't need to go that far to make it work. You can remove doesContain as a parameter and set it as a static instance variable and it worked for me.
public class Contains
{
private static boolean doesContain = false;
public static void main(String[] args)
{
System.out.println(contains("Java programming", "ogr"));
}
public static boolean contains(String haystack, String needle)
{
if(haystack.length() < needle.length())
{
return false;
}
else
{
for(int i = 0; i < needle.length(); i++)
{
if(haystack.charAt(i) != needle.charAt(i))
if((i + 1) == needle.length())
{
doesContain = false;
break;
}
else
break;
else
if((i + 1) == needle.length())
{
doesContain = true;
break;
}
else
continue;
}
char[] haystackChar = haystack.toCharArray();
char[] newCharArray = new char[(haystackChar.length - 1)];
for(int j = 1; j < haystackChar.length; j++)
{
newCharArray[j - 1] = haystackChar[j];
}
String newStr = new String(newCharArray);
if(doesContain == false)
contains(newStr, needle);
}
return doesContain;
}
}
What you had was very close, but by passing it as a parameter you were storing every time you went through another recursion. This way you only return your final value.
To find a needle in the haystack in the way you want, you don't need to use recursion.
Just remove the following lines of code from your function and it will work just fine:
char[] haystackChar = haystack.toCharArray();
char[] newCharArray = new char[(haystackChar.length - 1)];
for(int j = 1; j < haystackChar.length; j++)
{
newCharArray[j - 1] = haystackChar[j];
}
String newStr = new String(newCharArray);
if(doesContain == false)
contains(newStr, needle, doesContain);
I think you are sort of confusing yourself with the recursive function. One of the variables passed to the recursive function is doesContain, but the function is supposed to return whether the string contains it! In the lines
if(doesContain == false)
contains(newStr, needle, doesContain);
The call to contains will return if the substring contains the needle. You need to take that value, and return it back up the call stack.
Hopefully that made some sense. If that didn't, I'll give you the code so you can figure it out yourself:
public static boolean contains(String haystack, String needle)
{
if(haystack.length() < needle.length())
{
return false;
}
else
{
boolean doesContain=false;
for(int i = 0; i < needle.length(); i++)
{
if(haystack.charAt(i) != needle.charAt(i))
if((i + 1) == needle.length())
{
doesContain = false;
break;
}
else
break;
else
if((i + 1) == needle.length())
{
doesContain = true;
break;
}
else
continue;
}
char[] haystackChar = haystack.toCharArray();
char[] newCharArray = new char[(haystackChar.length - 1)];
for(int j = 1; j < haystackChar.length; j++)
{
newCharArray[j - 1] = haystackChar[j];
}
String newStr = new String(newCharArray);
if(doesContain == false)
return contains(newStr, needle);
else
return true;
}
}

Check if pattern exists in a String

I would like to check if a pattern exists in a String using iteration.
Here is what I have currently but I keep getting false as a result of it.
public static void main(String args[]) {
String pattern = "abc";
String letters = "abcdef";
char[] patternArray = pattern.toCharArray();
char[] lettersArray = letters.toCharArray();
for(int i = patternArray.length - 1; i<= 2; i++){
for(int j = lettersArray.length - 1; j <= 5;j++){
if(patternArray[i] == lettersArray[j]){
System.out.println("true");
} else{
System.out.println("false");
}
}
}
}
Basically I would like to check if abc exists in the String abcdef
Note: I don't want to use regex because is too easy. I am trying to find a solution without it because I am curious how to do it with iteration.
Here’s a naive string matching program that will find all matches of the pattern.
Not recommended for anything practical, because of the O(mn) time complexity (m and n are the lengths of the search string and pattern respectively).
class Potato
{
public static void main(String args[])
{
char[] search = "flow flow flow over me".toCharArray();
char[] pattern = "flow".toCharArray();
for(int i = 0; i <= search.length - pattern.length; i++)
// `-` don't go till the end of the search str. and overflow
{
boolean flag = true;
for(int j=0; j < pattern.length; j++)
{
if(search[i + j] != pattern[j])
{
flag = false;
break;
}
}
if (flag)
System.out.println("Match found at " + i);
}
}
}
Problem is you have two loops for each array. Here, you need single loop to traverse in both array using same index.
If you want to get all matches, i use a list to save matches addresses in the string.
String pattern = "abc";
String letters = "defabcdefabc";
int i = 0;
List<Integer> matches = new ArrayList();
while (i <= letters.length() - pattern.length()) {
if (letters.substring(i, i + pattern.length()).equals(pattern))
matches.add(i);
i += 1;
}
You can iterate matches if you want to loop all matches with this solution.
Edit:language changed
public static Boolean patternFinder(String str, String pattern){
for (int i = 0; i <= str.length()-pattern.length();i++){
Boolean found = true;
for (int f = 0; f < pattern.length();f++){
if (pattern.charAt(f) != str.charAt(i+f)){
found = false;
break;
}
}
if (found){
return true;
}
}
return false;
}
It's a very simple algorithm
basically, you loop through the string from the beginning and check if all the letters in the pattern are equal to the ones at that specific index.
Why not this:
public static void main(String args[]) {
String pattern = "abc";
String letters = "abcdef";
char[] patternArray = pattern.toCharArray();
char[] lettersArray = letters.toCharArray();
boolean matched = false;
for(int i = 0; i< lettersArray.length-patternArray.length && !matched; i++){
for(int j = 0; j < patternArray.length;j++){
if(patternArray[j] == lettersArray[i+j]&&j+1==patternArray.length){
matched = true;
System.out.println("true");
}
else if(i+1 == lettersArray.length-patternArray.length && j+1 == patternArray.length){
System.out.println("false");
}
}
}

Trouble breaking from a method

I am having difficulties with my method returning true. It is a boolean method that takes two words and tries to see if one can be turned into the other by transposing two neighboring letters. I have had no troubles getting the false boolean. When the code gets to the for loop with an if statement in it it runs fine but does not return true when the if statement is satisfied. For some reason it continues through the for loop. For example, when comparing "teh" and "the" when the loop hits 1 the if statement is satisfied but does not return true, the for lo
public static boolean transposable(String word1, String word2)
{
ArrayList<Character> word1char = new ArrayList<Character>();
ArrayList<Character> word2char = new ArrayList<Character>();
int word1length = word1.length();
int word2length = word2.length();
int count = 0;
String w1 = word1.toUpperCase();
String w2 = word2.toUpperCase();
if(word1length != word2length)
{
return false;
}
for(int i = 0; i < word1length; i++)
{
char letter1 = w1.charAt(i);
word1char.add(letter1);
char letter2 = w2.charAt(i);
word2char.add(letter2);
}
for(int i = 0; i < word1length; i++)
{
char w1c = word1char.get(i);
char w2c = word2char.get(i);
if(w1c == w2c)
{
count++;
}
}
if(count < word1length - 2)
{
return false;
}
for(int i = 0; i < word1length; i++)
{
char w1c = word1char.get(i);
char w2c = word2char.get(i+1);
if(w1c == w2c)
{
return true;
}
}
return false;
}
op just keeps running. What am I doing wrong?
As pointed out in the comments this doesn't seem to be the easiest way around this problem. Here is a solution which tries to follow your logic and includes the use of toUpperCase() and ArrayLists.
Going over your code it looks like you were getting a bit lost in your logic. This is because you had one method trying to do everything. Break things down into smaller methods and you also will benefit by not having to repeat code and it keeps things much cleaner. The code below is tested with Java8 (although there is no reason why this should not work with Java 7).
public static void main(String args[]) {
String word1 = "Hello";
String word2 = "Hlelo";
transposable(word1, word2);
}
private static boolean transposable(String word1, String word2) {
// Get an ArrayList of characters for both words.
ArrayList<Character> word1CharacterList = listOfCharacters(word1);
ArrayList<Character> word2CharacterList = listOfCharacters(word2);
boolean areWordsEqual;
// Check that the size of the CharacterLists is the same
if (word1CharacterList.size() != word2CharacterList.size()) {
return false;
}
// check to see if words are equal to start with
areWordsEqual = checkIfTwoWordsAreTheSame(word1CharacterList, word2CharacterList);
System.out.print("\n" + "Words are equal to be begin with = " + areWordsEqual);
if (!areWordsEqual) {
/*
This loop i must start at 1 because you can't shift an ArrayList index of 0 to the left!
Loops through all the possible combinations and checks if there is a match.
*/
for (int i = 1; i < word1CharacterList.size(); i++) {
ArrayList<Character> adjustedArrayList = shiftNeighbouringCharacter(word2CharacterList, i);
areWordsEqual = checkIfTwoWordsAreTheSame(word1CharacterList, adjustedArrayList);
System.out.print("\n" + "Loop count " + i + " words are equal " + areWordsEqual + word1CharacterList + adjustedArrayList.toString());
if (areWordsEqual) {
break;
}
}
}
return areWordsEqual;
}
// takes in a String as a parameter and returns an ArrayList of Characters in the order of the String parameter.
private static ArrayList<Character> listOfCharacters(String word) {
ArrayList<Character> wordCharacters = new ArrayList<Character>();
String tempWord = word.toUpperCase();
for (int wordLength = 0; wordLength < tempWord.length(); wordLength++) {
Character currentCharacter = tempWord.charAt(wordLength);
wordCharacters.add(currentCharacter);
}
return wordCharacters;
}
// takes in two character arrayLists, and compares each index character.
private static boolean checkIfTwoWordsAreTheSame(ArrayList<Character> characterList1, ArrayList<Character> characterList2) {
// compare list1 against list two
for (int i = 0; i < characterList1.size(); i++) {
Character currentCharacterList1 = characterList1.get(i);
Character currentCharacterList2 = characterList2.get(i);
if (!currentCharacterList1.equals(currentCharacterList2)) {
return false;
}
}
return true;
}
// this method takes in an ArrayList of characters and the initial index that we want to shift one place to the left.
private static ArrayList<Character> shiftNeighbouringCharacter(ArrayList<Character> characterListToShift, int indexToShiftLeft) {
ArrayList<Character> tempCharacterList = new ArrayList<Character>();
int indexAtLeft = indexToShiftLeft - 1;
// fill the new arrayList full of nulls. We will have to remove these nulls later before we can add proper values in their place.
for (int i = 0; i < characterListToShift.size(); i++) {
tempCharacterList.add(null);
}
//get the current index of indexToShift
Character characterOfIndexToShift = characterListToShift.get(indexToShiftLeft);
Character currentCharacterInThePositionToShiftTo = characterListToShift.get(indexAtLeft);
tempCharacterList.remove(indexAtLeft);
tempCharacterList.add(indexAtLeft, characterOfIndexToShift);
tempCharacterList.remove(indexToShiftLeft);
tempCharacterList.add(indexToShiftLeft, currentCharacterInThePositionToShiftTo);
for (int i = 0; i < characterListToShift.size(); i++) {
if (tempCharacterList.get(i) == null) {
Character character = characterListToShift.get(i);
tempCharacterList.remove(i);
tempCharacterList.add(i, character);
}
}
return tempCharacterList;
}
Hope this helps. If you are still struggling then follow along in your debugger. :)

Categories