This question already has answers here:
How to check if two words are anagrams
(37 answers)
Closed 7 years ago.
I have a problem with this little program in Java for which checks if 2 strings are anagrams or not.
I get a StringIndexOutOfBoundsException:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6
at java.lang.String.charAt(Unknown Source)
at AreAnagrams.areAnagrams(AreAnagrams.java:9)
at AreAnagrams.main(AreAnagrams.java:30)
This is my code:
public class AreAnagrams {
public static boolean areAnagrams(String a, String b) {
int j = 0;
int i = 0;
if (a.length() == b.length()) {
while (i < a.length()) {
if (a.charAt(i) == b.charAt(j)) {
j++;
i = 0;
} else {
i++;
if (j > a.length()) {
return false;
}
}
}
} else {
return false;
}
return false;
}
public static void main(String[] args) {
System.out.println(areAnagrams("momdad", "dadmom"));
}
}
java.lang.StringIndexOutOfBoundsException happens when you refer to a character index which exceeds the string length.
For example the string "dadmom" - when you call charAt(6), then it will throw this exception, because the character indices are in range from 0 to 5.
You can use the following code to identify anagrams:
public static boolean areAnagrams(String a, String b) {
char[] aChars = a.replaceAll("\\s", "").toCharArray();
char[] bChars = b.replaceAll("\\s", "").toCharArray();
Arrays.sort(aChars);
Arrays.sort(bChars);
System.out.println(aChars);
System.out.println(bChars);
return Arrays.equals(aChars, bChars);
}
public static void main(String[] args) {
System.out.println(areAnagrams("momdad", "dadmom"));
}
I feel that you have a programming logic error here. For anagrams the criteria should be that the starting from left to right for 1st string the characters should be equal for the 2nd string starting right to left.
I did not find any such thing in your code. I feel you should try the following inside your if block if ( a.length() == b.length()):
int length = a.length();
for(int i = 0; i < length; i++){
if(a.charAt(i) != b.charAt(length-i-1)){
return false;
}
}
return true;
You should also remove the declaration of i and j variables in your code.
Correction
I really got confused with anagram and palindrome. The above answer is correct for palindrome. I am adding to my answer to work for anagram.
I would suggest that you check the strings recursively by changing the method areAnagrams as illustrated below:
public static boolean areAnagrams(String a, String b) {
//If the length of strings is unequal then return false.
if(a.length() != b.length()){
return false;
}
//Else if the length of strings equals 1 return the equality of the two strings
if(a.length() == 1){
return a.equals(b);
}
//Else replace the first occurrence of the first character
//of variable `a` with blank string in string variable b.
//Here if the character is not present in string b then the
//variable b remains unchanged and the length of b would be
//greater than that of variable `a` in the next recursion.
b = b.replaceFirst(a.substring(0, 1), "");
//remove the first character in string `a`
a = a.substring(1, a.length());
//make the recursive call
return areAnagrams(a, b);
}
Related
I am trying to write a method which returns the number of times the first character of a string appears throughout the string. This is what I have so far,
public int numberOfFirstChar0(String str) {
char ch = str.charAt(0);
if (str.equals("")) {
return 0;
}
if ((str.substring(0, 1).equals(ch))) {
return 1 + numberOfFirstChar0(str.substring(1));
}
return numberOfFirstChar0(str);
}
however, it does not seem to work (does not return the correct result of how many occurrences there are in the string). Is there anything wrong with the code? Any help is appreciated.
This uses 2 functions, one which is recursive. We obtain the character at the first index and the character array from the String once instead of doing it over and over and concatenating the String. We then use recursion to continue going through the indices of the character array.
Why you would do this I have no idea. A simple for-loop would achieve this in a much easier fashion.
private static int numberOfFirstChar0(String str) {
if (str.isEmpty()) {
return 0;
}
char[] characters = str.toCharArray();
char character = characters[0];
return occurrences(characters, character, 0, 0);
}
private static int occurrences(char[] characters, char character, int index, int occurrences) {
if (index >= characters.length - 1) {
return occurrences;
}
if (characters[index] == character) {
occurrences++;
}
return occurrences(characters, character, ++index, occurrences);
}
Java 8 Solution
private static long occurrencesOfFirst(String input) {
if (input.isEmpty()) {
return 0;
}
char characterAtIndexZero = input.charAt(0);
return input.chars()
.filter(character -> character == characterAtIndexZero)
.count();
}
Here is a simple example of what you are looking for.
Code
public static void main(String args[]) {
//the string we will use to count the occurence of the first character
String countMe = "abcaabbbdc";
//the counter used
int charCount=0;
for(int i = 0;i<countMe.length();i++) {
if(countMe.charAt(i)==countMe.charAt(0)) {
//add to counter
charCount++;
}
}
//print results
System.out.println("The character '"+countMe.charAt(0)+"' appears "+ charCount+ " times");
}
Output
The character 'a' appears 3 times
Example: String a = "ACAHBBA" and String b = "ABAB" should return true, since both strings can spell ABAB.
I have tried with contains(), but that only works for equal sequences.
// The code should look like this.
public class task10 {
public static boolean contains(String a, String b) {
// check if b can be spelled using characters from a.
// if it can. return true.
// else
return false;
}
}
Posible solution?
public static boolean contains(String a, String b) {
for (int i = 0; i < b.length(); i++) {
if (a.indexOf(b.charAt(i)) == -1) {
return false;
}
}
return true;
}
Simply iterate thru one string and get the index of the character. If >= 0, replace character with non-alphabetic character and repeat. This algorithm presumes the need to match the correct number of characters. For example, hello would return false if the character set was helo.
public static boolean spelledFrom(String word, String chars) {
StringBuilder sb = new StringBuilder(chars);
for (String c : word.split("")) {
int i;
if ((i = sb.indexOf(c)) < 0) {
return false;
}
sb.setCharAt(i, '#');
}
return true;
}
You can try this:
public static boolean canSpell(String a, String b)
{
String shorter = (a.length() <= b.length()) ? a : b;
String longer = (shorter.equals(a)) ? b : a;
for(int i = 0; i < shorter.length(); i++)
{
if(!longer.contains("" + shorter.charAt(i)))
return false;
}
return true;
}
Once you've identified the shorter string, you just need to verify that each of its chars are contained in the longer string. This solution doesn't verify if a char "has already been used", which means inserting "AB" and "ABBA" will return true. If you need to do this, you just need to delete the verified char from the longer string in every loop.
I have to make a method named 'contains' that accepts a string and a character as parameters and returns true if that character occurs two or more times in the string.
example: Input contains("Apple", 'p') should return "True"
private boolean contains(String a,char b) {
if(a.contains(b)) {
print("true");
}
else {
print("");
}
//boolean c = a.contains('l');
return false;
}
I know this code is wrong ... I want to know what I have to do and what I have to fix .
I would appreciate your advice
Thank you.
There are a few ways to do this but the simplest would just be to loop through the String looking for the char, if count reaches two then return true.
For this consider using
for (char c : input) {
if (c == myChar) count++;
if (count >= 2) return true;
}
return false;
Another way would be to use String.replace and replace the wanted char with ""
then compare the size of the before and after String
Your method may return a boolean based on the size difference between the original string, and the string without the given character :
return (a.length() - (a.replace(b, '')).length()) >= 2 ;
In theoretical terms:
First: you need to iterate over the input string characters using a for loop and then in each iteration compare the current character in the string with the other character argument which is given as method argument. If they match, then you can increase a counter (a variable). Then compare if the counter value is 2 and return true immediately it is so. At the method end you can return false just like you have done already.
Second : you are printing true , not returning true. Should use return true; when the value of variable becomes 2
countMatches(a,b) returns the count of b in String a. and it is from org.apache.commons.lang3
private boolean contains(String a,char b) {
return StringUtils.countMatches(a, b)>=2 ;
}
or in simple java you can use
private boolean contains(String a,char b) {
return (a.length() - a.replaceAll(String.valueOf(b),"").length())>=2 ;
}
This is one of simple ways to do this. Here the string is put into char array. This way it is easier to examine the elements of the char array and find out same characters.
private boolean contains(String a, char b) {
char[] c_array = a.toCharArray();
int count = 0;
for (int i = 0; i < c_array.length; i++) {
if (b == c_array[i]) {
count++;
continue;
} else {
continue;
}
}
if (count >= 2) {
return true;
} else {
return false;
}
}
public class Demo {
public static boolean contains(String str,char c){
//todo:check str for NullPointExecption
int flag=0;
for(int i=0;i<str.length();i++){
if(c==str.charAt(i)){
flag++; //if str contains char c,flag=flag+1
}
if(flag>=2){
return true; //if flag>=2,return true
}
}
return false;
}
public static void main(String[] args) {
System.out.println(contains("appple", 'p'));//result is true
}
}
I've written a function to find whether a given string (stripped of spaces) is a palindrome. Unfortunately, it takes too long to run. Any ideas how I can make the below code run faster? (I'm timing out on LeetCode's Online Judge):
public class Solution {
public boolean checkIfPalindrome(String s) {
if (s.length() == 0 || s.length() == 1) {
return true;
}
//if first letter == last letter
char first = s.charAt(0);
char second = s.charAt(s.length() - 1);
if (first == second) {
String shorterString = s.substring(1, s.length() - 1);
return isPalindrome(shorterString);
} else {
return false;
}
}
public String onlyCharacters(String s) {
String toReturn = "";
for (Character c : s.toCharArray()) {
if (Character.isLetter(c)) {
toReturn += c;
}
}
return toReturn;
}
public boolean isPalindrome(String s) {
s = onlyCharacters(s);
return checkIfPalindrome(s);
}
}
This isn't the most optimal way of finding if a string is palindrome or not.
Just loop through n/2 iterations (where n is length of string) and check if character at position i is equal to character at position n-i
If the length of the string s is n then s will be a palindrome if
s[i]=s[n-1-i] for i in range [0,ceil(n/2)] // 0 based index
Code:
public static boolean checkIfPalindrome(String s) {
for(int i=0;i<s.length()/2;i++) {
if(s.charAt(i)!=s.charAt(s.length()-i-1)) {
return false;
}
}
return true;
}
It's an algorithm method called "divide and conquer". But in this case is just to make it n/2 instead of n.
Here is a suitable algorithm that might just help :
1.For i = 1 to n/2
2.If string[i] = string[n-1] then continue in the loop
3.Else break and return false
4.return true
If n is the length of the input string, your code takes O(n^2) operations. This may surprise you because there are no nested loops in your code, but both the substring method and the += operator for Strings require the creation of a new String, which requires copying its contents.
To see this in action, I have inserted
System.out.println(s);
into the isPalindrome() and checkIfPalindrome() methods, and invoked
isPalindrome("doc, note: i dissent. a fast never prevents a fatness. i diet on cod");
This produces the following output:
docnoteidissentafastneverpreventsafatnessidietoncod
ocnoteidissentafastneverpreventsafatnessidietonco
ocnoteidissentafastneverpreventsafatnessidietonco
cnoteidissentafastneverpreventsafatnessidietonc
cnoteidissentafastneverpreventsafatnessidietonc
noteidissentafastneverpreventsafatnessidieton
noteidissentafastneverpreventsafatnessidieton
oteidissentafastneverpreventsafatnessidieto
oteidissentafastneverpreventsafatnessidieto
teidissentafastneverpreventsafatnessidiet
teidissentafastneverpreventsafatnessidiet
eidissentafastneverpreventsafatnessidie
eidissentafastneverpreventsafatnessidie
idissentafastneverpreventsafatnessidi
idissentafastneverpreventsafatnessidi
dissentafastneverpreventsafatnessid
dissentafastneverpreventsafatnessid
issentafastneverpreventsafatnessi
issentafastneverpreventsafatnessi
ssentafastneverpreventsafatness
ssentafastneverpreventsafatness
sentafastneverpreventsafatnes
sentafastneverpreventsafatnes
entafastneverpreventsafatne
entafastneverpreventsafatne
ntafastneverpreventsafatn
ntafastneverpreventsafatn
tafastneverpreventsafat
tafastneverpreventsafat
afastneverpreventsafa
afastneverpreventsafa
fastneverpreventsaf
fastneverpreventsaf
astneverpreventsa
astneverpreventsa
stneverprevents
stneverprevents
tneverprevent
tneverprevent
neverpreven
neverpreven
everpreve
everpreve
verprev
verprev
erpre
erpre
rpr
rpr
p
p
That's quite a wall of text we are asking the computer to compute! We also see that every String is created twice. That's because you needlessly invoke onlyCharacters() in every iteration.
To avoid creating intermediary String instances, you can use a String Builder:
String onlyCharacters(String s) {
StringBuilder toReturn = new StringBuilder();
for (Character c : s.toCharArray()) {
if (Character.isLetter(c)) {
toReturn.append(c);
}
}
return toReturn.toString();
}
Also, it turns out a StringBuilder has a cool method called reverse(), so we can simplify your program to:
boolean isPalindrome(String s) {
StringBuilder letters = new StringBuilder();
for (Character c : s.toCharArray()) {
if (Character.isLetter(c)) {
letters.append(c);
}
}
StringBuilder reversedLetters = new StringBuilder(letters).reverse();
return onlyLetters.equals(reversedLetters);
}
This code only creates 2 StringBuilder objects rather than n Strings, and is therefore about n/2 times faster than your code.
I found this to be faster than any other answer so far:
public class Solution {
public boolean isPalindrome(String s) {
for (int low = 0, high = s.length() - 1;; low++, high--) {
char cLow = 0, cHigh = 0;
// Find the next acceptable character for the increasing index.
while (low < high && !Character.isLetterOrDigit(cLow = s.charAt(low))) {
low++;
}
// Find the previous acceptable character for the decreasing index.
while (low < high && !Character.isLetterOrDigit(cHigh = s.charAt(high))) {
high--;
}
if (low >= high) {
// All previous character comparisons succeeded and we have a palindrome.
return true;
}
if (Character.toUpperCase(cLow) != Character.toUpperCase(cHigh)) {
// This is not a palindrome.
return false;
}
}
}
}
You have only one object: your original String. Every character is tested until we get acceptable characters (Character.isLetter). Then only those are compared.
No temporary object, no superflous checks. Straight to the goal: it does one thing but does it well.
Note: this answers the actual Leetcode OJ answer by checking alphanumerics instead of only letters and by not caring about the case.
You may use this StringBuilder.reverse() to check Palindrome:
private boolean isPalindrome(String str) {
StringBuilder strBuilder = new StringBuilder(str);
return str.equals(strBuilder.reverse().toString());
}
Can someone please discuss and explain a way I can modify my code to function with these test cases... I am trying to make my program take a word and make it a palindrome by replacing one letter in a word that prevents the word from being a palindrome
Desired test cases:
Palindromes.isPalindrome2("cat", 'c') => true
Palindromes.isPalindrome2("axaa", 'x') => true
Palindromes.isPalindrome2("12bb", 'b') => true
Palindromes.isPalindrome2("ca", 'c') => true
This is what I have thus far...
public class Palindromes {
public static boolean isPalindrome(String word) {
//Strip out non-alphanumeric characters from string
String cleanWord = word.replaceAll("[^a-zA-Z0-9]","");
//Check for palindrome quality recursively
return checkPalindrome(cleanWord);
}
public static boolean isPalindrome2(String word) {
//Strip out non-alphanumeric characters from string
String cleanWord = word.replaceAll("[^a-zA-Z0-9]","");
//Check for palindrome quality recursively
return checkPalindrome2(cleanWord);
}
public static boolean checkPalindrome(String word) {
if(word.length() < 2) {
return true;
}
char first = word.charAt(0);
char last = word.charAt(word.length()-1);
if(first != last) {
return false;
}
else {
return checkPalindrome(word.substring(1,word.length()-1));
}
}
public void replace(int first, int last) {
if(first != last)
{ first = last;}
else if(last != first)
{ last = first;}
}
public static boolean checkPalindrome2(String word) {
char special = 0;
if(word.length() < 2) {
return true;
}
char first = word.charAt(0);
char last = word.charAt(word.length()-1);
if(first != last) {
return false;
}
if(first != last)
return false;
else {
return checkPalindrome2(word.substring(1,word.length()-1));
}
}
}
replace() was my attempt at handling the wildcard letter, but I cant seem to find the appropriate solution... All help will be greatly appreciated. thanks...
Here's my steps I would do:
Split the received string into 2 substrings. The first string front being the front half of the string, the second string back being the half end of the string.
Example:
char replacement = 'c';
String input = "aabbcc";
StringBuilder front = new StringBuilder(input.substring(0, input.length()/2));
// Do modulus to not include the odd middle (it mirrors itself)
StringBuilder back = new StringBuilder(input.substring((input.length()/2)+(input.length()%2));
Compare the two strings, replacing if one matches but the other doesn't. If neither match each other and is not the given 'replacement' character, return false. If you do more than one replacement, return false (since that is what you said the requirement is)
Example:
int replacements = 0;
for (int i=0; i < front.length(); ++i)
{
int backIndex = back.length() - i;
if (front.charAt(i) != back.charAt(backIndex))
{
// Characters do not match at all to given replacement
if ((front.charAt(i) != replacement) &&
(back.charAt(backIndex) != replacement)
{
// Cannot make it
// (Or if you want to force it, set both to replacement
// by deleting this one if statement)
return false;
}
// Front matches replacement
else if (front.charAt(i) == replacement)
{
// Replace back character with replacement
back.setCharAt(backIndex, replacement);
replacements++;
}
// Back matches replacement
else if (back.charAt(backIndex) == replacement)
{
// Replace front character with replacement
front.setCharAt(i, replacement);
replacements++;
}
if (replacements > 1)
{
// Can only replace one
return false;
}
}
}
String output = front.toString() + back.toString();
Here's my code, it splits the input into two halves, and compares the first half to the reversed second half. If they are equal, the input is already a palindrome. If they are not equal, it iterates through the first half, exchanging letters with the input char to replace with, and comparing with the reversed second half at every step. Then it does the same thing, but using the second half instead of the first half:
public class CanMakePalindrome {
public static void main(String[] args) {
System.out.println("cat using c: " + canMakePalindrome("cat", 'c'));
System.out.println("axaa using x: " + canMakePalindrome("axaa", 'x'));
System.out.println("12bb using b: " + canMakePalindrome("12bb", 'b'));
System.out.println("ca using c: " + canMakePalindrome("ca", 'c'));
}
private static boolean canMakePalindrome(String input, char c) {
int length = input.length();
String start = input.substring(0, length/2);
String end = input.substring(length/2+length%2, length); // need modulus in the case of odd length input
return (replaceLoop(start,end, c) || replaceLoop(end,start, c));
}
private static boolean replaceLoop(String start, String end, char c) {
if (start.equals(reverse(end))) {
System.out.println("Input is already a palindrome.");
return true;
}
for (int i=0; i<start.length(); i++) {
char[] startchars = start.toCharArray();
char[] endchars = end.toCharArray();
endchars = reverse(endchars);
startchars[i] = c;
if ((new String(startchars).equals(new String(endchars)))) return true;
}
return false;
}
private static char[] reverse(char[] input) {
int length = input.length;
char[] reversed = new char[length];
for (int i=0;i<length;i++) {
reversed[length-i-1]=input[i];
}
return reversed;
}
private static String reverse(String input){
String reversed = new String(reverse(input.toCharArray()));
return reversed;
}
}
Output:
cat using c: true
axaa using x: true
12bb using b: false
ca using c: true
Note that 12bb cannot be made into a palindrome using only one character change, so your test case appears to not match your specifications of replacing only one letter. Also my code will return true if given an empty string as input.