Java takes long to convert a 5 letter word to numbers - java

Before I start I would like to inform you that I am a total beginner to Java so excuse my uneducated mistakes. I have been trying to program an application to encrypt a message. During this process, the input gets converted to a number to allow mathematical expressions. The problem is when trying to convert. The actual code does work, but takes a rather long time to convert a 5 letter word, which is the word "Hello"( it takes around 10 seconds or so). Below is the method where the input gets converted. `
public static void encrypt(String plainText) {
Random random = new Random();
plainText =plainText.toUpperCase();
char[] storedInput = plainText.toCharArray();
int[] convertedInput = new int[plainText.length()];
for (int indexSelector = 0, comparisonNumber = 1; indexSelector < plainText.length(); comparisonNumber++) {
if( storedInput[indexSelector] == ' ') {
System.out.print(" <SPACE> ");
}
else {
if( ((int) storedInput[indexSelector]-64) == comparisonNumber) {
int converter = storedInput[indexSelector] - 64;
convertedInput[indexSelector] = converter;
System.out.print(convertedInput[indexSelector]);
}
else {
continue;
}
}
}
}
This code takes an input (hello), turns all letters to upper case, and then when I get the integer I subtract 64 because it returns the ASCII integer. After this A becomes 1, B becomes 2, C becomes 3 and so on....
When I try to convert hello (or any other words) it takes at least 8 seconds. Any suggestions on why?

You need to simplify your program. comparisonNumber is causing you significant problems, and you generally should avoid multiple variables in your for loop unless you really know what you are doing. Even in professional settings I would consider a , in a for loop a problem that needs to be justified.
In your case you are looping on comparisonNumber but never using it for anything but verifying you hit the right number, where you then ignore the value and do operations that are independent of it. Since you don't reset the value, it loops through all the possible values before continuing to process the next letter.
Here is a version that might be closer to what you are looking for, I just removed that variable and left everything else as is.
public static void encrypt(String plainText) {
Random random = new Random();
plainText.toUpperCase();
char[] storedInput = plainText.toCharArray();
int[] convertedInput = new int[plainText.length()];
for (int indexSelector = 0; indexSelector < plainText.length(); indexSelector++) {
if( storedInput[indexSelector] == ' ') {
System.out.print(" <SPACE> ");
} else {
int converter = storedInput[indexSelector] - 64;
convertedInput[indexSelector] = converter;
System.out.print(convertedInput[indexSelector]);
indexSelector++;
}
}

Related

letter change, what am I doing wrong?

So im trying the following challenge:
Using the Java language, have the function LetterChanges(str) take the str parameter being passed andmodify it using the following algorithm. Replace every letter in the string with the letter following it in thealphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
This is my code
class LetterChange {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char currentChar,letter;
int i = 0;
while (i < str.length())
{
currentChar = str.charAt(i);
for(int x = 0; x < alphabet.length(); x++)
{
letter = alphabet.charAt(x);
if (currentChar == letter){
str = str.replace(currentChar,alphabet.charAt(x+1));
i++;
}
}
}
when I run it it is returning the last char in string +1 letter in alphabet. for example if i was to run "bcd" it returns "EEE". I dont understand why its replacing all chars with the result of the loop for the last char.
When you go through the loop the first time you get
"bcd"--> "ccd"
Now, str.replace will turn this into "ddd" on next turn, then "EEE".
I.e., replace replaces every occurrence on each turn.
It is true that debugging it in the IDE will help you in the future!
Also, what if you had a lowercase vowel in your string?
public class Alphabet {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char[] string = str.toLowerCase().toCharArray();
for (int i=0; i < string.length; i++) {
char d = alphabet.charAt(((alphabet.toLowerCase().indexOf(string[i]))+1) % 26);
string[i]=d;
}
return new String(string);
}
public static void main(String[] args) {
System.out.println(Alphabet.LetterChanges("aabb"));
}
}
alphabet.charAt(
((alphabet.toLowerCase().indexOf(string[i]))
+1) % 26)
1) use toLowerCase on the input and your string map to eliminate case problems
2) find character at index+1 in string map 'alphabet', treating it as a circular buffer using a modulus that takes z to a.
index 25 (z) + 1 == 26 --> 0 (A) because 26 is 0 mod 26 while index 0(A) + 1 = 1 --> 1 mod 26. It is only necessary to wrap the z to A while not changing the other 25 indices and is more efficient than branching with an "if" statement.
Does this solution help?
public static String letterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
StringBuilder stringBuilder = new StringBuilder();
for (char letter : str.toCharArray()) {
if (alphabet.contains(Character.toString(letter))) {
int index = alphabet.indexOf(letter) + 1;
if (index >= 26) {
index = 0;
}
stringBuilder.append(alphabet.charAt(index));
}
}
return stringBuilder.toString();
}
The previous solution was hard to follow, so it's difficult to explain why it wasn't working without debugging through it to see where it goes wrong. It was easier to use a for-each loop to go through the str parameter and find matches using Java's provided methods like .indexOf and .charAt.
Also, Java uses lower camel case method naming, letterChanges instead of LetterChanges :)
Let me know if you have any questions.
You are getting that result because on every replacing you are re-setting the input string. I recommend you:
Better try with two different variables: Let the input variable be unmodified, and work on the output one.
Since strings are unmodifiable -as you already know- better declare them as arrays of char.
For the shake of optimization, base your algorithm on one single loop, which will iterate over the characters of the input string. For each character, decide if it is alphabetic or not, and in case it is, what character should it be replaced with.

The Creation of The Encryption Key for a Keyword Cipher in My Code (Java)

I was just wondering if I could get some help with a question involving keyword ciphers.
The following code is supposed to create the encryption key for a keyword cipher (the key that states how your input (let's say "this is a secret message") became ("qabp bp k poynoq hoppkdo")). The key is, therefore, a String or char array. My teacher had us use a char array. For the case above, the key would {KEYWORDABCFGHIJLMNPQSTUVXZ}, and the basic alphabet would correspond to this {ABCDEFGHIJKLMNOPQRSTUVWXYZ}, therefore A would become K, I would become A, and so on and so forth.
But, anways, back to the problem at hand, when I try to create the key, the first loop that you see below works perfectly fine adding in the keyword for the first values of the array; however, after this adding in the rest of the array (the rest of the alphabet not including or skipping the letters of the keyword) doesn't seem to work in the second loop.
I don't exactly know what I am doing wrong, but I would guess it would have to do with one of the if statements, or the java keyword (continue;) that I use in the loop. Because it appears that when I print the keyword array, it comes out to {KEYWORDABCDEFGHIJKLMONPQRS} leaving out the last seven letters of the alphabet instead of the letters that already occur in the word, KEYWORD.
If you could help fix the code, or get me on the right track, that would be much appreciated. If you have an question on the question, fell free to ask in the comment section below/
Thank you so much for all your help!
public class Crytograph
{
private String in;
private String out;
//private int awayFrom;
private char [] keyword;
private String word;
public Crytograph(String input, String wordLY) // , int fromAway )
{
in = input.toLowerCase();
out = "";
awayFrom = fromAway;
word = wordLY;
keyword = new char[26];
int counter = 97;
int counter1 = 0;
for (int x = 0; x < word.length(); x++)
{
keyword[x] = word.charAt(x);
}
for (int i = word.length(); i < 26; i++)
{
if ((char)(counter) == keyword[counter1])
{
continue;
}
else
{
keyword[i] = (char)(counter);
//System.out.println(keyword[i]);
}
counter++;
counter1++;
if (counter1 == word.length())
{
counter1 = 0;
}
}
}
You're comparing each new character to a single character at index counter1. But you really need to compare it to all the characters in word. Even if you happen to find a match, continue; will still increment i, meaning your array will be missing one or more characters at the end. Try this instead:
char c = 'a' - 1;
for (int i = word.length(); i < 26; i++) {
// loop until we find a char not contained in `word`
while (word.contains(String.valueOf(++c)));
keyword[i] = c;
}

Having trouble with for loops

So, I need to write a program using loops that takes a string and counts what and how many letters appear in that string. (string "better butter" would print "b appears 2 times, e appears 3 times, ' '(space) appears 1 time, and so on). While I understand the idea and concept behind this assignment, actually pulling it off has been rough.
My nested for loop is where the problems are coming from, I assume. What I've written only loops once (i think) and just shows the first character and says there's only one of that character.
Edit: Preferably without using Map or arrays. I'm fine with using them if it's the only way, but they've not been covered in my class so I'm trying to avoid them. Every other similar question to this (that I've found) uses Map or array.
import java.util.Scanner;
class myString{
String s;
myString() {
s = "";
}
void setMyString(String s) {
this.s = s;
}
String getMyString() {
return s;
}
String countChar(String s){
s = s.toUpperCase();
int cnt = 0;
char c = s.charAt(cnt);
for (int i = 0; i <= s.length(); i++)
for (int j = 0; j <= s.length(); j++) //problem child here
c = s.charAt(cnt);
cnt++;
if (cnt == 1)
System.out.println(c+" appears "+cnt+" time in "+s);
else
System.out.println(c+" appears "+cnt+" times in "+s);
return "for"; //this is here to prevent complaint from the below end bracket.
}
}
public class RepeatedCharacters {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s;
System.out.println("Enter a sentence: ");
s = in.nextLine();
myString myS = new myString();
// System.out.println(myS.getMyString());
// System.out.println(myS.countChar());
myS.countChar(s);
}
}
First you will need to scan the entire string and store the
counts of each characters. Later you can just print the counts.
Algorithm 1:
Use a HashMap to store the character as key and its count as value. (If you are new to Java, you might want to read up on
HashMaps.)
Every time you read a character in your for loop, check if it present in the HashMap. If yes, then increment the count by 1. Else
add a new characters to the map with count 1.
Printing:
Just iterate on your HashMap and print out the character and
their respective counts.
Issue with your code: You are trying to print the count as soon as you
read a character. But the character might appear again later in the
string. So you need to keep track of the characters you have already
read.
Algorithm 2:
String countChar(String s){
has_processed = []
for i = 0 to n
cnt = 0
if s.charAt(i) has been processed
continue;
for j = i+1 to n
if (s.charAt(i) == s.charAt(j))
cnt++
add s.charAt(i) to has_processed array
print the count of s.charAt(i)
}
Use a frequency array to get an answer in linear time.
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String s = "better butter";
int freq[] = new int[26];
int i;
for (i = 0; i < s.length(); i++) {
if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z')
freq[s.charAt(i)-'a']++;
}
for (i = 0; i < freq.length; i++) {
if (freq[i] == 0) continue;
System.out.println((char)(i+'a') + " appears " + freq[i] + " times" );
}
}
}
Ideone Link
Note that this can be expanded to include uppercase letters, but for demonstrative purposes, only lowercase letters are handled in the above code.
EDIT: While the OP did ask if it was possible to do this without an array, I would recommend against such. That solution would have terrible time complexity and repeat character counts (unless an array is used to keep track of seen characters, which is counter to the aim). Thus, the above solution is the best way to do it in a reasonable amount of time (linear) with limited space consumption.
I would do the following. Create a HashMap which keeps track of which unique characters are in the string and the count for each character.
You only need to iterate over the string once, and put each character into the HashMap. if the characer is in the map, icrement the integer count in the map, else add 1 to the map for that character. Print out the map with toString() to get the result. The whole thing can be done in about 4 lines of code.
The only thing being done in your nested for loop with the following
c = s.charAt(cnt)
is setting the c char to the value of the first letter (i.e. index 0 of the string) over and over and over until you've looped through the string n^2 times. In other words, you're not incrementing your cnt counter within the for loops at all.
Suggestion: try to use meaningful names for your variables; it will help you a lot in your career. Also class names should always start with a capital letter.
Although it is not the quickest solution in terms of performance, the most simple solution should be:
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);
Source: Most efficient way to increment a Map value in Java
Please next time use the search function before posting a new question.
Here is my version of countChar(String s)
boolean countChar(String s) {
if(s==null) return false;
s = s.toUpperCase();
//view[x] will means that the characted in position x has been just read
boolean[] view = new boolean[s.length()];
/*
The main idea is:
foreach character c = s.charAt(x) in the string s, I have a boolean value view[x] which say if I have already examinated c.
If c has not been examinated yet, I search for other characters equals to c in the rest of the string.
When I found other characters equals to c, I mark it as view and I increment count with count++.
*/
for (int i = 0; i < s.length(); i++) {
if (!view[i]) {
char tmp = s.charAt(i);
int count = 0;
for (int j = i; j < s.length(); j++) {
if (!view[j] && s.charAt(j) == tmp) {
count++;
view[j] = true;
}
}
System.out.println("There were " + count + " " + tmp);
}
}
return true;
}
It should work, excuse me for my English because I'm italian

Char replacement (without using replace)

This code is a series of tasks, the first is it replace all 'F' in sentence string to a 'f' without using the .replace() method. Which i've done, then after that I'm supposed to replace all the 'f's to blanks, which I sort of done but for some reason all my capital 'F's change to a weird square. Any ideas? I know it's basic code but baby steps.
Here is my weird output: "There was a isherman named []isher who ished or some ish in a issure; till a ish with a grin, pulled the isherman in. Now they’re ishing the issure or []isher."
Thanks! Rob.
public static void main(String[] args) {
// orginal string sentence
String sentence = ("There was a fisherman named Fisher who fished for some fish in a fissure; till a fish with a grin, pulled the fisherman in. Now they’re fishing the fissure for Fisher. ");
// data
char[] originalArray = sentence.toCharArray();
int i = 0;
int sLength = sentence.length();
int positionArray[];
// combining an int to the array position
positionArray = new int[sLength];
/* while loop to check the position of any 'F' or 'f' characters in sentence and identifying it's array position*/
while (i < sLength) {
char charAt = sentence.charAt(i);
if (charAt == 'F') {
originalArray[i] = 0;
positionArray[i] = 1;
}
i++;
}
//redeclaring int i to 0 for the new array
i = 0;
//reassigning the character 'F' or 'f' to just 'f to 'sentence'
sentence = new String(originalArray);
char[] newArray = sentence.toCharArray();
while (i < sLength) {
if (positionArray[i] == 1) {
newArray[i] = 'f';
}
i++;
//redeclaring int i to 0 for the (part e)
i = 0;
//removing every occurance of 'f' (part e)
while (i < sLength) {
if (newArray[i] == 'f' ) {
newArray[i] = ' ';
}
i++;
//printing to console
}
sentence = new String(newArray);
System.out.println(sentence);
}
}
Here is a solution using Java 8. It uses the fact that a String is a CharSequence, and that you can obtain an IntStream of either the characters or code points in it; this solution uses chars:
// Turn all 'F's into 'f's
private int bigFToSmallF(final int inputChar)
{
return 'F' == inputChar ? 'f' : inputChar;
}
// Turn all 'f's into '0's
private int smallFToZero(final int inputChar)
{
return 'f' == inputChar ? '0' : inputChar;
}
private String anyFToZeroes(final String input)
{
final StringBuilder sb = new StringBuilder(input.length());
input.chars().map(this::bigFToSmallF).map(this::smallFToZero)
.forEach(sb::appendCodePoint);
return sb.toString();
}
Plug this code into a main and you're done.
No errors for me. Works fine in win cmd and in eclipse. I had a similar problem some time ago. For me the issue was that there was an error in my installed fonts. Just some Win update has currupted something, don't know why. After I manually reinstalled my std fonts everything worked fine. Additionally to the problem also was within the "space". When I checked the hex value in debug view, the value was slightely off and so a different character was displayed.
Check your code indentation.
Your idea is correct, although is not optimized.
You've implemented 3 loops, but the last while is a inner loop.
I think you wanted to implement 3 'independent' loops, check out the brackets placement.

Java - Help converting letter to integer, adding 5, then converting back to letter

First off, here is my code so far
public int encrypt() {
/* This method will apply a simple encrypted algorithm to the text.
* Replace each character with the character that is five steps away from
* it in the alphabet. For instance, 'A' becomes 'F', 'Y' becomes '~' and
* so on. Builds a string with these new encrypted values and returns it.
*/
text = toLower;
encrypt = "";
int eNum = 0;
for (int i = 0; i <text.length(); i++) {
c = text.charAt(i);
if ((Character.isLetter(c))) {
eNum = (int) - (int)'a' + 5;
}
}
return eNum;
}
(text is the inputted string by the way. And toLower makes the string all lower case to make it easier converting.)
I got most of my assignment done, but one part of it is tasking me with moving every letter inputted 5 spaces over. A becomes F, B becomes G, etc.
So far from I got the letter converted to a number, but I am having trouble adding to it and then returning it back to a letter.
When I run the program and I enter my input such as "abc" I get '8'. It just adds them all up.
Any help would be much appreciated, and I can post the full code if necessary.
Few issues -
First of all - eNum = (int) - (int)'a' + 5; you do not need the first (int) - i believe, you can just do - eNum = (int)c + 5; . Your expression would always result in a negative integer.
Instead of returning eNum you should convert it to character and add it to a string and return the string at end (or you can create a character array of same length as string , keep storing the characters in the array, and return a string created from the character array).
Instead of using a in the condition , you should use c which denotes the current character at the ith index.
I am guessing not all of the variables in your code are member variables (instance variables) of the class , so you should define them with a datatype in your code.
Example changes to your code -
String text = toLower; //if toLower is not correct, use a correct variable to get the data to encrypt from.
String encrypt = "";
for (int i = 0; i <text.length(); i++) {
char c = text.charAt(i);
if ((Character.isLetter(c))) {
encrypt += (char)((int)c + 5);
}
}
return encrypt;
//Just a quick conversion for testing
String yourInput = "AbC".toLowerCase();
String convertedString = "";
for (int i = 0; i <text.length(); i++) {
char c = yourInput.charAt(i);
int num = Character.getNumericValue(c);
num = (num + 5)%128 //If you somehow manage to pass 127, to prevent errors, start at 0 again using modulus
convertedString += Integer.toString(num);
}
System.out.println(convertedString);
Hope this is what you're looking for.
Try something like this, I believe this has several advantages:
public String encrypt(String in) {
String workingCopy = in.toLowerCase();
StringBuilder out = new StringBuilder();
for (int i = 0; i < workingCopy.length(); i++) {
char c = workingCopy.charAt(i);
if ((Character.isLetter(c))) {
out.append((char)(c + 5));
}
}
return out.toString();
}
This code is a little bit verbose, but perhaps then it is easier to follow. I introduced the StringBuilder because it is more efficient than doing string = string + x

Categories