The question is as follows:
A pangram is a string that contains every letter of the alphabet. Given a sentence determine whether it is a pangram in the English alphabet. Ignore case. Return either pangram or not pangram as appropriate.
My code works for all input except "qmExzBIJmdELxyOFWv LOCmefk TwPhargKSPEqSxzveiun", for which it returns "not pangram", even though the correct answer is "pangram." Does anybody have any ideas as to why my code is outputting the incorrect solution?
public static String pangrams(String s) {
Hashtable<Character, Integer> alpha = new Hashtable<Character, Integer>();
s = s.toLowerCase();
for (int i = 0; i < s.length()-1; i++){
if (alpha.get(s.charAt(i)) != null){
int value = alpha.get(s.charAt(i));
alpha.put(s.charAt(i), value + 1);
}
else{
alpha.put(s.charAt(i), 1);
}
}
if (alpha.size() != 27){
return "not pangram";
}
else{
return "pangram";
}
}
As per your definition of pangram you might want to consider the following:
Use a Set instead of a Map
As far as I know, English has 26 letters
Make sure you don't mistakenly add digits or symbols to your set
Given the three above statements I would slightly change your code to reflect that. That would, more or less, look something like this:
public static String pangrams(String s) {
Set<Character> alpha = new HashSet<>();
s = s.toLowerCase();
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if (Character.isLetter(c)){
alpha.add(c);
}
}
if (alpha.size() == 26){
return "pangram";
}
return "not pangram";
}
Related
I have to compare two string arrays. If the any of the characters in myArray match a character in argArray then I need to swap the case of the character in myArray. I'm almost there but am getting extra output.
This is what I have so far -
public class Main {
public static void main(String[] args) {
Main ob = new Main();
ob.reverse("bcdxyz#3210.");
}
public String reverse(String arg) {
String reverseCap = "";
String myStr = "abc, XYZ; 123.";
char[] argArray = arg.toCharArray();
char[] myArray = myStr.toCharArray();
for (int i =0; i < myArray.length; i++) {
for (int j =0; j < argArray.length; j++){
if (myArray[i] == argArray[j] && Character.isLowerCase(myArray[i])){
reverseCap += Character.toUpperCase(myArray[i]);
} else if (myArray[i] == argArray[j] && Character.isUpperCase(myArray[i])){
reverseCap += Character.toLowerCase(myArray[i]);
} else {
reverseCap += myArray[i];
}
}
}
System.out.println(reverseCap);
return null;
}
I want reverseCap to be "aBC, xyz, 123." but am getting the following -
"aaaaaaaaaaaaBbbbbbbbbbbbcCcccccccccc,,,,,,,,,,,, XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZZZZZ;;;;;;;;;;;; 111111111111222222222222333333333333............
".
I've been staring at this for hours so I figured it was time to ask for help before I pluck my eyes out.
Marce noted the problem of adding characters to reverseCap on every iteration. Here is a solution that solves that problem and performs the case changes in place. Checking for a match first and then changing the case simplifies the logic a bit. Note myArray[i] needs to be lowercased before checking against arg[i] because the former may be an uppercase character; this is not needed for argArray[j] because those characters are assumed to be all lowercase. Finally, once the inner loop has matched, further iterations of it are no longer needed.
public class Main {
public static void main(String[] args) {
Main ob = new Main();
String testStr = "abc, XYZ; 123.";
String testArg = "bcdxyz#3210.";
System.out.println(testStr + " using " + testArg + " =>");
System.out.println(ob.reverse(testStr, testArg));
}
public String reverse(String myStr, String myArg) {
char[] myArray = myStr.toCharArray();
char[] argArray = myArg.toCharArray();
for (int i =0; i < myArray.length; i++) {
for (int j =0; j < argArray.length; j++) {
if (Character.toLowerCase(myArray[i]) == argArray[j]) {
if (Character.isLowerCase(myArray[i])) {
myArray[i] = Character.toUpperCase(myArray[i]);
} else if (Character.isUpperCase(myArray[i])) {
myArray[i] = Character.toLowerCase(myArray[i]);
}
break;
}
}
}
return String.valueOf(myArray);
}
}
With this part
} else {
reverseCap += myArray[i];
}
you're adding a character to reverseCap with every iteration, regardless if the characters match or not.
In your specific example, you could just leave that out, since every character in myStr also appears in arg, but if you want to add characters to reverseCap, even if they don't appear in arg, you'll need a way of checking if you already added a character to reverseCap.
Change
String reverseCap = "";
to
char[] reverseCap = new char[myStr.length()];
and then for each occurrence of
reverseCap +=
change that to read
reverseCap[i] =
Finally, convert reverseCap to a String:
String result = String.valueOf(reverseCap);
You are currently returning null. Consider returning result, and moving the System.out.println(...) into the main() method.
Update:
I think a better way to approach this is to use a lookup map containing upper/lower case pairs and their inverse to get the replacement character. The nested for loops are a bit gnarly.
/**
* Example: for the string "bcdxyz#3210."
* the lookup map is
* {B=b, b=B, C=c, c=C, D=d, d=D, X=x, x=X, Y=y, y=Y, Z=z, z=Z}
* <p>
* Using a map to get the inverse of a character is faster than repetitively
* looping through the string.
* </p>
* #param arg
* #return
*/
public String reverse2(String arg) {
Map<Character, Character> inverseLookup = createInverseLookupMap(arg);
String myStr = "abc, XYZ; 123.";
String result = myStr.chars()
.mapToObj(ch -> Character.toString(inverseLookup.getOrDefault(ch, (char) ch)))
.collect(Collectors.joining());
return result;
}
private Map<Character, Character> createInverseLookupMap(String arg) {
Map<Character, Character> lookupMap = arg.chars()
.filter(ch -> Character.isLetter(ch))
.mapToObj(this::getPairs)
.flatMap(List::stream)
.collect(Collectors.toMap(Pair::key, Pair::value));
System.out.println(lookupMap);
return lookupMap;
}
private List<Pair> getPairs(int ch) {
char upperVariant = (char) Character.toUpperCase(ch);
return List.of(
new Pair(upperVariant, Character.toLowerCase(upperVariant)),
new Pair(Character.toLowerCase(upperVariant), upperVariant));
}
static record Pair(Character key, Character value) {
}
But if one is not used to the Java streaming API, this might look a bit gnarly too.
I'm trying to practice for a techniqual test where I have to count the number of characters in a DNA sequence, but no matter what I do the counter won't update, this is really frustrating as I learnt code with ruby and it would update, but Java seems to have an issue. I know there's something wrong with my syntaxt but for the life of me I can't figure it out.
public class DNA {
public static void main(String[] args) {
String dna1 = "ATGCGATACGCTTGA";
String dna2 = "ATGCGATACGTGA";
String dna3 = "ATTAATATGTACTGA";
String dna = dna1;
int aCount = 0;
int cCount = 0;
int tCount = 0;
for (int i = 0; i <= dna.length(); i++) {
if (dna.substring(i) == "A") {
aCount+= 1;
}
else if (dna.substring(i) == "C") {
cCount++;
}
else if (dna.substring(i) == "T") {
tCount++;
}
System.out.println(aCount);
}
}
}
It just keeps returning zero instead of adding one to it if the conditions are meet and reassigning the value.
Good time to learn some basic debugging!
Let's look at what's actually in that substring you're looking at. Add
System.out.println(dna.substring(i));
to your loop. You'll see:
ATGCGATACGCTTGA
TGCGATACGCTTGA
GCGATACGCTTGA
CGATACGCTTGA
GATACGCTTGA
ATACGCTTGA
TACGCTTGA
ACGCTTGA
CGCTTGA
GCTTGA
CTTGA
TTGA
TGA
GA
A
So, substring doesn't mean what you thought it did - it's taking the substring starting at that index and going to the end of the string. Only the last character has a chance of matching your conditions.
Though, that last one still won't match your condition, which is understandably surprising if you're new to the language. In Java, == is "referential equality" - when applied to non-primitives, it's asserting the two things occupy the same location in memory. For strings in particular, this can give surprising and inconsistent results. Java keeps a special section of memory for strings, and tries to avoid duplicates (but doesn't try that hard.) The important takeaway is that string1.equals(string2) is the correct way to check.
It's a good idea to do some visibility and sanity checks like that, when your program isn't doing what you think it is. With a little practice you'll get a feel for what values to inspect.
Edward Peters is right about misuse of substring that returns a String.
In Java, string must be places between double quotes. A String is an object and you must use method equals to compare 2 objects:
String a = "first string";
String b = "second string";
boolean result = a.equals(b));
In your case, you should consider using charAt(int) instead. Chars must be places between simple quotes. A char is a primitive type (not an object) and you must use a double equals sign to compare two of them:
char a = '6';
char b = 't';
boolean result = (a==b);
So, your code should look like this:
public class DNA {
public static void main(String[] args) {
String dna1 = "ATGCGATACGCTTGA";
String dna2 = "ATGCGATACGTGA";
String dna3 = "ATTAATATGTACTGA";
String dna = dna1;
int aCount = 0;
int cCount = 0;
int tCount = 0;
for (int i = 0; i < dna.length(); i++) {
if (dna.charAt(i) == 'A') {
aCount += 1;
} else if (dna.charAt(i) == 'C') {
cCount++;
} else if (dna.charAt(i) == 'T') {
tCount++;
}
System.out.println(aCount);
}
}
}
substring(i) doesn't select one character but all the characters from i to the string length, then you also made a wrong comparison: == checks 'object identity', while you want to check that they are equals.
You could substitute
if (dna.substring(i) == "A")
with:
if (dna.charAt(i) == 'A')
this works because charAt(i) returns a primitive type, thus you can correctly compare it to 'A' using ==
One of the problems, as stated, was the way you are comparing Strings. Here is a way
that uses a switch statement and a iterated array of characters. I put all the strings in an array. If you only have one string, the outer loop can be eliminated.
public class DNA {
public static void main(String[] args) {
String dna1 = "ATGCGATACGCTTGA";
String dna2 = "ATGCGATACGTGA";
String dna3 = "ATTAATATGTACTGA";
String[] dnaStrings =
{dna1,dna2,dna3};
int aCount = 0;
int cCount = 0;
int tCount = 0;
int gCount = 0;
for (String dnaString : dnaStrings) {
for (char c : dnaString.toCharArray()) {
switch (c) {
case 'A' -> aCount++;
case 'T' -> tCount++;
case 'C' -> cCount++;
case 'G' -> gCount++;
}
}
}
System.out.println("A's = " + aCount);
System.out.println("T's = " + tCount);
System.out.println("C's = " + cCount);
System.out.println("G's = " + gCount);
}
prints
A's = 14
T's = 13
C's = 6
G's = 10
I am trying to generate a String as a hint for the solution to a world solve.
This is what I have for generating the hint, but I am unsure of how to correct these errors. If the guess has the correct character guessed in the right place, the hint displays that character. If it has the letter in the word, it displays a "+" in the respective position. If the letter isn't in the word, a "*" gets returned.
For instance, if the solution to the puzzle is "HARPS", and the guess is "HELLO", the hint will be "H****". Likewise if the guess is "HEART", the hint will be "H*++*".
Also, wordLength is generated from another method that gives the amount of characters in the solution.
public String getHint(String theGuess) {
for (int index = 0; index < wordLength; index++) {
if **(theGuess.charAt(index)** = solution.charAt(index)) {
hint.**setCharAt**(index, theGuess.charAt(index));
} else if **(theGuess.charAt(index)** = solution.indexOf(solution)) {
**hint.setCharAt**(index, "+");
} else {
**hint.setCharAt**(index, "*");
}
}
return hint;
}
Errors are double starred.
For (theGuess.charAt(index) Eclipse is showing the following error message:
The left-hand side of an assignment must be a variable.
For hint.setCharAt, it tells me:
The method setCharAt(int, String) is undefined for the type String.
There are numerous problems in your code that need to be fixed:
= is used when you want to assign a new value to a variable. You want to use == when comparing two values.
setCharAt() is a method for StringBuilder, not String. This simplest solution is to just concatinate your new charater to the String using +=.
If you want to use StringBuilder, the following parts need to be fixed:
The second parameter for setCharAt() should be a character, not a string. You need to change the double quotes around "*" and "+" to single quotes like '*'
setCharAt() tries to replace a character at a specifc index. This will throw an error if the StringBuilder is shorter than the index position you are trying to replace. You can solve this by right away setting your StringBuilder to a string that is the correct length like
hint = new StringBuilder("*****").
Since you are always adding the the end of the builder though, you should really just use append() instead of setCharAt() and you won't need to worry about this index position problem.
(theGuess.charAt(index) == solution.indexOf(solution) does not search the entire solution string to see if it contains the current character. Instead, you can use indexOf() to check if the string contains the character. This link might help: How can I check if a single character appears in a string?
Here is a complete program with the code working:
public class HelloWorld
{
public static void main(String[] args)
{
OtherClass myObject = new OtherClass();
System.out.print(myObject.getHint("HEART"));
}
}
Option 1 - Add to the String using +=:
public class OtherClass
{
private String solution = "HARPS";
private int wordLength = 5;
public String getHint(String theGuess) {
String hint = "";
for (int index = 0; index < wordLength; index++) {
if (theGuess.charAt(index) == solution.charAt(index)) {
hint += theGuess.charAt(index);
} else if (solution.indexOf(theGuess.charAt(index)) > 0) {
hint += "+";
} else {
hint += "*";
}
}
return hint;
}
}
Option 2 - Use StringBuilder:
public class OtherClass
{
private StringBuilder hint;
private String solution = "HARPS";
private int wordLength = 5;
public String getHint(String theGuess) {
hint = new StringBuilder();
for (int index = 0; index < wordLength; index++) {
if (theGuess.charAt(index) == solution.charAt(index)) {
hint.append(theGuess.charAt(index));
} else if(solution.indexOf(theGuess.charAt(index)) > 0) {
hint.append('+');
} else {
hint.append('*');
}
}
return hint.toString();
}
}
This code should work:
public String getHint(String theGuess) {
StringBuilder hintBuilder = new StringBuilder(hint);
for (int index = 0; index < wordLength; index++) {
if (theGuess.charAt(index) == solution.charAt(index)) {
hintBuilder.setCharAt(index, theGuess.charAt(index));
} else if(theGuess.charAt(index) == solution.indexOf(string)) {
hintBuilder.setCharAt(index, "+");
} else {
hintBuilder.setCharAt(index, "*");
}
}
return hintBuilder;
}
Basically, you have to use a 'StringBuilder' because Strings are immutable, meaning that they cannot be altered once they are built.
Also, when comparing two values, use == or === to compare, not =.
UPDATED
I forgot that Strings are immutable in Java, and have updated the code so that it should work.
I want to use hashtable to find unique characters as it seems more efficient to me so for example, hello in hashtable would be=> {h:1,e:1,l:2,o:1} & since value is more than 1 then string isnt unique. I know I can do ascii way of counting unique characters but I want to implement the hashtable way.
Please note, I do not want a regex implementation.
static void findHashUnique(String str)
{
Hashtable<Character, Integer> ht = new Hashtable<Character, Integer>();
for(int i=0;i<str.length();i++)
{
int cnt=1;
if(!ht.containsKey(str.charAt(i)))
{
ht.put(str.charAt(i), cnt);
}
}
System.out.print(ht);
}
I am stuck at the part of how will I first initialize the hashtable & also check if value exists then increment. In case of 'l' it will increment to 2 instead of being 1 since the key is the same.
Also Is this solution efficient?
Here's my approach.
String string = "hello";
Hashtable<Character, Integer> map = new Hashtable<>();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
map.put(c, 1);
}
}
System.out.println(map);
Output: {e=1, o=1, l=2, h=1}
Well, I don't know exactly what character encodings you will be examining, but if you are constraining yourself to only ASCII characters, you can use a simple array of 128 elements.
public static String uniqueLetters(String s) {
// storage for ascii characters
char[] letters = new char[128];
// mark counts of all letters
for(int i = 0; i < s.length(); i++) {
letters[ (int)s.charAt(i) ]++;
}
// find unique letters
String uniques = "";
for(int i = 0; i < letters.length; i++) {
if ( letters[i] == 1 ) {
uniques += Character.toString( (char)letters[i] );
}
}
return uniques;
}
To "fix" your code, use a HashSet<Character>, which uses a Hashtable internally, but you don't have to know or worry about that. Just keep adding the chars to the set and you'll be left with a unique set of chars at the end.
To achieve the intention more easily:
String uniqueChars = str.replaceAll("(.)(?=.*\\1)", "");
String handling in Java is something I'm trying to learn to do well. Currently I want to take in a string and replace any characters I find.
Here is my current inefficient (and kinda silly IMO) function. It was written to just work.
public String convertWord(String word)
{
return word.toLowerCase().replace('á', 'a')
.replace('é', 'e')
.replace('í', 'i')
.replace('ú', 'u')
.replace('ý', 'y')
.replace('ð', 'd')
.replace('ó', 'o')
.replace('ö', 'o')
.replaceAll("[-]", "")
.replaceAll("[.]", "")
.replaceAll("[/]", "")
.replaceAll("[æ]", "ae")
.replaceAll("[þ]", "th");
}
I ran 1.000.000 runs of it and it took 8182ms. So how should I proceed in changing this function to make it more efficient?
Solution found:
Converting the function to this
public String convertWord(String word)
{
StringBuilder sb = new StringBuilder();
char[] charArr = word.toLowerCase().toCharArray();
for(int i = 0; i < charArr.length; i++)
{
// Single character case
if(charArr[i] == 'á')
{
sb.append('a');
}
// Char to two characters
else if(charArr[i] == 'þ')
{
sb.append("th");
}
// Remove
else if(charArr[i] == '-')
{
}
// Base case
else
{
sb.append(word.charAt(i));
}
}
return sb.toString();
}
Running this function 1.000.000 times takes 518ms. So I think that is efficient enough. Thanks for the help guys :)
You could create a table of String[] which is Character.MAX_VALUE in length. (Including the mapping to lower case)
As the replacements got more complex, the time to perform them would remain the same.
private static final String[] REPLACEMENT = new String[Character.MAX_VALUE+1];
static {
for(int i=Character.MIN_VALUE;i<=Character.MAX_VALUE;i++)
REPLACEMENT[i] = Character.toString(Character.toLowerCase((char) i));
// substitute
REPLACEMENT['á'] = "a";
// remove
REPLACEMENT['-'] = "";
// expand
REPLACEMENT['æ'] = "ae";
}
public String convertWord(String word) {
StringBuilder sb = new StringBuilder(word.length());
for(int i=0;i<word.length();i++)
sb.append(REPLACEMENT[word.charAt(i)]);
return sb.toString();
}
My suggestion would be:
Convert the String to a char[] array
Run through the array, testing each character one by one (e.g. with a switch statement) and replacing it if needed
Convert the char[] array back to a String
I think this is probably the fastest performance you will get in pure Java.
EDIT: I notice you are doing some changes that change the length of the string. In this case, the same principle applies, however you need to keep two arrays and increment both a source index and a destination index separately. You might also need to resize the destination array if you run out of target space (i.e. reallocate a larger array and arraycopy the existing destination array into it)
My implementation is based on look up table.
public static String convertWord(String str) {
char[] words = str.toCharArray();
char[] find = {'á','é','ú','ý','ð','ó','ö','æ','þ','-','.',
'/'};
String[] replace = {"a","e","u","y","d","o","o","ae","th"};
StringBuilder out = new StringBuilder(str.length());
for (int i = 0; i < words.length; i++) {
boolean matchFailed = true;
for(int w = 0; w < find.length; w++) {
if(words[i] == find[w]) {
if(w < replace.length) {
out.append(replace[w]);
}
matchFailed = false;
break;
}
}
if(matchFailed) out.append(words[i]);
}
return out.toString();
}
My first choice would be to use a StringBuilder because you need to remove some chars from the string.
Second choice would be to iterate throw the array of chars and add the treated char to another array of the inicial size of the string. Then you would need to copy the array to trim the possible unused positions.
After that, I would make some performance tests to see witch one is better.
I doubt, that you can speed up the 'character replacement' at all really. As for the case of regular expression replacement, you may compile the regexs beforehand
Use the function String.replaceAll.
Nice article similar with what you want: link
Any time we have problems like this we use regular expressions are they are by far the fastest way to deal with what you are trying to do.
Have you already tried regular expressions?
What i see being inefficient is that you are gonna check again characters that have already been replaced, which is useless.
I would get the charArray of the String instance, iterate over it, and for each character spam a series of if-else like this:
char[] array = word.toCharArray();
for(int i=0; i<array.length; ++i){
char currentChar = array[i];
if(currentChar.equals('é'))
array[i] = 'e';
else if(currentChar.equals('ö'))
array[i] = 'o';
else if(//...
}
I just implemented this utility class that replaces a char or a group of chars of a String. It is equivalent to bash tr and perl tr///, aka, transliterate. I hope it helps someone!
package your.package.name;
/**
* Utility class that replaces chars of a String, aka, transliterate.
*
* It's equivalent to bash 'tr' and perl 'tr///'.
*
*/
public class ReplaceChars {
public static String replace(String string, String from, String to) {
return new String(replace(string.toCharArray(), from.toCharArray(), to.toCharArray()));
}
public static char[] replace(char[] chars, char[] from, char[] to) {
char[] output = chars.clone();
for (int i = 0; i < output.length; i++) {
for (int j = 0; j < from.length; j++) {
if (output[i] == from[j]) {
output[i] = to[j];
break;
}
}
}
return output;
}
/**
* For tests!
*/
public static void main(String[] args) {
// Example from: https://en.wikipedia.org/wiki/Caesar_cipher
String string = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG";
String from = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String to = "XYZABCDEFGHIJKLMNOPQRSTUVW";
System.out.println();
System.out.println("Cesar cypher: " + string);
System.out.println("Result: " + ReplaceChars.replace(string, from, to));
}
}
This is the output:
Cesar cypher: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
Result: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD