Decrease the space complexity of finding certain letters in String in Java - java

Problem
I have a problem that finding certain letters in a given String cost too much memory which caused a "Memory Limit Exceeded". I am wondering the reason of it. The question and my codes are below.
Question
describe: Find the number of times the vowels a, e, i, o, u appear in a string.
Enter: Enter a line of string, the string length is less than 80 characters. So the characters are all lowercase letters.
Output: Output a line, and output the number of times a, e, i, o, u appear in the input string in sequence, and the integers are separated by spaces.
Codes
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int[] count = new int[5]; // refers to 'a' 'e' 'i' 'o' 'u'
Scanner buf = new Scanner(System.in);
String input = buf.nextLine();
buf.close();
for(int i = 0; i < input.length(); i++) {
switch(input.charAt(i)) {
case 'a':
++count[0];
break;
case 'e':
++count[1];
break;
case 'i':
++count[2];
break;
case 'o':
++count[3];
break;
case 'u':
++count[4];
break;
}
}
for(int item: count) {
System.out.print(item);
System.out.print(' ');
}
}
}

Summary
Deleted the call of the Scanner class and read characters one by one directly from System.in
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
int[] count = new int[5]; // a e i o u
int temp = System.in.read();
while(temp != '\n') {
switch(temp) {
case 'a': // 97
++count[0];
break;
case 'e':
++count[1];
break;
case 'i':
++count[2];
break;
case 'o':
++count[3];
break;
case 'u':
++count[4];
break;
}
temp = System.in.read();
}
// System.in.close();
for(int item: count) {
System.out.print(item);
System.out.print(' ');
}
}
}

Related

Switch case increment only adding once to array

I have to get a text input from the user and then I have to replace every vowel a,e,i,o,u for 1,2,3,4,5 and show the amount of replacements for every vowel and then also the changed text.
The problem is the text at the end looks nicely replaced but the amount of replacements show up as 1.
(I tried doing it below counting the 1,2,3,4 and 5s in "myText" and it works perfect but it also counts if the user inputs a number so that is a problem)
Heres the first part:
public static void replaceAndCount(String myText, int[] vowels) {
for (int i = 0; i < myText.length(); i++) {
switch (myText.charAt(i)) {
case 'a':
vowels[0]++;
myText = myText.replace('a', '1');
case 'e':
vowels[1]++;
myText = myText.replace('e', '2');
case 'i':
vowels[2]++;
myText = myText.replace('i', '3');
case 'o':
vowels[3]++;
myText = myText.replace('o', '4');
case 'u':
vowels[4]++;
myText = myText.replace('u', '5');
}
}
}
You have 2 issues in your code.
You have to use break in each case, otherwise all the cases below the matching case will be executed as well. Example,
case 'a':
vowels[0]++;
myText = myText.replace('a', '1');
break;
case 'e':
vowels[1]++;
myText = myText.replace('e', '2');
break;
String replace(old,new) will replace all occurrences of the old character with new. That is why, amount of replacements show up as 1.
Refer this for string replacement at specific index
Hope this below code works for you
Code :
public class ReplaceVowels {
public static void main(String[] args) {
String myText = "aaaeiou";
int[] vowels = new int[5];
replaceAndCount(myText.toLowerCase(), vowels);
}
private static void replaceAndCount(String text, int[] vowels) {
StringBuilder myText = new StringBuilder(text);
for (int i = 0; i < myText.length(); i++) {
switch (myText.charAt(i)) {
case 'a':
vowels[0]++;
myText.setCharAt(i, '1');
break;
case 'e':
vowels[1]++;
myText.setCharAt(i, '2');
break;
case 'i':
vowels[2]++;
myText.setCharAt(i, '3');
break;
case 'o':
vowels[3]++;
myText.setCharAt(i, '4');
break;
case 'u':
vowels[4]++;
myText.setCharAt(i, '5');
}
}
for (int vowel : vowels) {
System.out.println(vowel);
}
System.out.println(myText);
}
Results
You can refer this for replacing single character

How to convert certain characters in a sentence using if else statements?

my program so far only works if you enter one letter. How would I alter the program so it works with a complete sentence?
Scanner input = new Scanner(System.in);
System.out.print("Enter the string to be converted: ");
String convert = input.nextLine();
if(convert.equals("a")){
System.out.print("#");
}
else{
if(convert.equals("e")){
System.out.print("$");
}
An example:
Enter the string to be converted: abcde
The converted string is: #bcd$
Your program will work only for an input consisting of one character e.g. if you input a, it will print # and if you input e, it will print $ and so on (if you add other vowels too in your program). It is because you are comparing (and replacing) the whole input string rather than comparing (and replacing) the character(s) of the input string.
There are many ways in which you can do it. A couple of them are as follows:
Get an array of characters out of the input string and then iterate the array to process the printing as per your requirement e.g.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter the string to be converted: ");
String convert = input.nextLine();
for (char ch : convert.toCharArray()) {
switch (ch) {
case 'a':
System.out.print('#');
break;
case 'e':
System.out.print('$');
break;
case 'i':
System.out.print('^');
break;
case 'o':
System.out.print('*');
break;
case 'u':
System.out.print('&');
break;
default:
System.out.print(ch);
}
}
}
}
A sample run:
Enter the string to be converted: coronavirus
c*r*n#v^r&s
Replace the characters as per your requirements using String::replace e.g.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter the string to be converted: ");
String convert = input.nextLine();
convert = convert.replace('a', '#').replace('e', '$').replace('i', '^').replace('o', '*').replace('u', '&');
System.out.println(convert);
}
}
A sample run:
Enter the string to be converted: coronavirus
c*r*n#v^r&s
You have to add this instead of your if sentences:
for (int i = 0; i < convert.length(); i++ { //This loop will repeat the same times that the String's lenght
switch (convert.charAt(i) {
case 'a': System.out.print("#");
break;
case 'e': System.out.print("$");
break;
case 'i': System.out.print("&");
break;
case 'o': System.out.print("#"); // Here you put the letter to replace.
break;
default: // This code will execute if there's a option you didn't put on the cases
}
}

How can I convert a hexadecimal number into binary without using parse or automatic conversion

Below I have a method named 'hextoBinary' that returns a hexadecimal to binary conversion through type void.
In order for me to continue with my program I need a conversion from hex to binary method that returns and int so I can convert that binary int into a decimal with my 'hextoDecimal' method.
Can anybody help me or guide me on what approach to take, i've been stuck on this for a while now. i am limited to doing this manually instead of using parse or java automatic conversions.
import java.io.*;
import java.util.Scanner;
import java.util.ArrayList;
public class Main
{
static void hexToBinary(char hexdec[])
{
for (char c: hexdec)
{
switch (c)
{
case '0':
System.out.print("0000");
break;
case '1':
System.out.print("0001");
break;
case '2':
System.out.print("0010");
break;
case '3':
System.out.print("0011");
break;
case '4':
System.out.print("0100");
break;
case '5':
System.out.print("0101");
break;
case '6':
System.out.print("0110");
break;
case '7':
System.out.print("0111");
break;
case '8':
System.out.print("1000");
break;
case '9':
System.out.print("1001");
break;
case 'A':
System.out.print("1010");
break;
case 'B':
System.out.print("1011");
break;
case 'C':
System.out.print("1100");
break;
case 'D':
System.out.print("1101");
break;
case 'E':
System.out.print("1110");
break;
case 'F':
System.out.print("1111");
break;
default:
System.out.print("\nInvalid hexadecimal digit " + hexdec[c]);
}
}
}
public static int hextoDecimal(int n)
{
int decimal = 0, p = 0;
while(n != 0)
{
decimal += ((n % 10) * Math.pow(2,p));
n = n / 10;
p++;
}
return decimal;
}
public static void main(String[] args) throws IOException
{
Scanner sc = new Scanner(new File("RAMerrors8x4c"));
ArrayList<String> hexValues = new ArrayList<>();
while(sc.hasNext())
{
hexValues.add(sc.nextLine());
}
hexToBinary(hexValues.get(0).toCharArray());
}
}
This code is based on some that came from here but that link no longer seems to be active. Anyway, from a hex string you can get an int like this:
int hexToDecimal(String s){
int result = 0;
int digit = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= '0' && c <= '9')
digit = c - '0';
else
if (c >= 'A' && c <= 'F')
digit = 10 + c - 'A';
else
inputError(s);
result = 16 * result + digit;
}
return result
}
I modified your code a little.
a. In your code only the first hex was printed.
Change:
call hexToBinary for every hex String.
b. the binary value was discarded after printing, so it couldn't be reused.
Change:
Changed returntype of hexToBinary from void to String and returned the binary value calculated.
To be able to return a String I add the peaces(nibbles) of the hex/binary to a String in every switch(case) clause.(a Stringbuilder might be better than a String - you can additionally improve that)
in the main: additionally collect all the returned binary values in a arraylist called "binaryValues" in order to have them for the next step.
With the above (little) changes I now have all the binary values that had already been calculated.
So I am able to simply use them in a binaryToDecimal method which just sums up the binary values weighted by their position.
Why not do it again? Because youd need to convert the A-F to numbers what your hexToBinary already did. So storing the values saves you doing that step again. I have a feeling that is what your teacher had in mind when he/she combined the tasks like this.
The resulting code is:
import java.io.*;
import java.util.Scanner;
import java.util.ArrayList;
public class Main
{
static String hexToBinary(char hexdec[]) {
String hex = "";
for (char c : hexdec) {
switch (c) {
case '0':
System.out.print("0000");
hex += "0000";
break;
case '1':
System.out.print("0001");
hex += "0001";
break;
case '2':
System.out.print("0010");
hex += "0010";
break;
case '3':
System.out.print("0011");
hex += "0011";
break;
case '4':
System.out.print("0100");
hex += "0100";
break;
case '5':
System.out.print("0101");
hex += "0101";
break;
case '6':
System.out.print("0110");
hex += "0110";
break;
case '7':
System.out.print("0111");
hex += "0111";
break;
case '8':
System.out.print("1000");
hex += "1000";
break;
case '9':
System.out.print("1001");
hex += "1001";
break;
case 'A':
System.out.print("1010");
hex += "1110";
break;
case 'B':
System.out.print("1011");
hex += "1111";
break;
case 'C':
System.out.print("1100");
hex += "1100";
break;
case 'D':
System.out.print("1101");
hex += "1110";
break;
case 'E':
System.out.print("1110");
hex += "1110";
break;
case 'F':
hex += "1111";
System.out.print("1111");
break;
default:
System.out.print("\nInvalid hexadecimal digit " + hexdec[c]);
}
}
System.out.println();
return hex;
}
public static int binaryToDecimal(String binary) {
int decimal = 0;
for (int i = 1; i < binary.length()-1; i++) {
decimal += Math.pow(2, i-1) * (binary.charAt(binary.length()-i) - '0');
}
return decimal;
}
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new File("RAMerrors8x4c"));
ArrayList<String> hexValues = new ArrayList<>();
ArrayList<String> binaryValues = new ArrayList<>();
while (sc.hasNext()) {
hexValues.add(sc.nextLine());
}
for (String hex : hexValues) {
String binary = hexToBinary(hex.toCharArray());
binaryValues.add(binary);
System.out.println(binary);
}
for (String binary : binaryValues) {
int decimal = binaryToDecimal(binary);
System.out.println(decimal);
}
}
}
}
Besides using a Stringbuilder another idea could be to do all the printing of the binary values in the main. The hexToBinary returns the String - so you can print it in the loop - if you want.

Java - Assign a number and a word to a string of inputted characters

I am new to Java and I am trying to make a program that will take a string, such as 'asdfg', and print words and a total number that are associated with these letters.
So 'a' would be 'apple' and its assigned number is 10, 's' would be spinach, and its assigned number is 5, 'd' would be 'dog' and its assigned number would be 15, 'f' would be 'frog' and its assigned number would be 20 and 'g' would be 'goat' and its assigned number would be 25. The output would look something like 'apple spinach dog frog goat 75'.
The code I have so far is
import java.util.Scanner;
import java.util.ArrayList;
import java.io.*;
public class PizzaTwo {
public static void main(String[] args) throws Exception {
Scanner scan = new Scanner(System.in);
System.out.println("Please enter the details of your order");
String myList = scan.nextLine();
for (int i = 0; i < myList.length(); i++) {
int letNum = 0;
switch (myList.charAt(i)) {
case 'a':
System.out.println("apple" + letNum);
letNum += 10;
break;
case 's':
System.out.println("spinach" + letNum);
letNum += 5;
break;
case 'd':
System.out.println("dog" + letNum);
letNum += 15;
break;
case 'f':
System.out.println("frog" + letNum);
letNum += 20;
break;
case 'g':
System.out.println("goat", letNum);
letNum += 25;
break;
default:
System.out.println("Nothing..");
break;
}
}
}
}
Thank you for any help.
First of all, I'd like to suggest you use better names for variables.
You were resetting the "letNum" in each loop, then I've moved it out of the loop.
I recommend read about String and StringBuilder.
String objects are immutable, so instead to create more variables to concatenate "flavors", I used StringBuilder that are mutable.
Strings are constant; their values cannot be changed after they are created
The principal operations on a StringBuilder are the append and insert methods, which are overloaded so as to accept data of any type
import java.util.Scanner;
public class PizzaTwo {
public static void main(String[] args) throws Exception {
Scanner scan = new Scanner(System.in);
System.out.println("Please enter the details of your order");
String flavors = scan.nextLine();
int price = 0;
StringBuilder order = new StringBuilder();
for (int i = 0; i < flavors.length(); i++) {
switch (flavors.charAt(i)) {
case 'a':
order.append("apple ");
price += 10;
break;
case 's':
order.append("spinach ");
price += 5;
break;
case 'd':
order.append("dog ");
price += 15;
break;
case 'f':
order.append("frog ");
price += 20;
break;
case 'g':
order.append("goat ");
price += 25;
break;
default:
order.append("No flavor added ");
break;
}
}
System.out.println(order.append(price));
}
}
It looks like you want the numbers to only appear after all the words have been printed, from your description "apple spinach dog frog goat 75", but your code looks like it's trying to append the number to the end of each word.Assuming you want the output to be like your sample output, don't try to print the numbers after each word, instead after all the words have been printed print the variable you've been using to accumulate each letters value, 'letNum' in your code.Also, don't reset 'letNum' each time you deal with a new letter.
Take 2 separate variables, 1 string and another number. Each time concatenate with existing string, means something like String s=""; int n=0; s+="Apple"; n+=10; s+="frog";
....
Now when loop is done print string then the number.

Java: Lighter code for encryption

I'm trying to get a program to encrypt a message using Cesar's Cypher, which involves replacing every character of a string with the letter, whose code is the code of the replaced letter plus 3. For e.g., if the letter is A, then it has to be replaced with D, because the code of D is the code of A plus 3. The letters are case-sensitive. The code I thought of uses a really heavy switch construct, I was wondering, if you could help me to make it more straight forward.
Here's the code I use for the encryption method:
public class Util
{
public static String Encript(String stringa)
{
char[] stringaArray=stringa.toCharArray();
for (int i =0; i<stringaArray.length; i++)
{
switch (stringaArray[i])
{
case 'a':
stringaArray[i]=('D');
break;
case 'b':
stringaArray[i]='E';
break;
case 'c':
stringaArray[i]='F';
case 'd':
stringaArray[i]='G';
break;
case 'e':
stringaArray[i]='H';
break;
case 'f':
stringaArray[i]='I';
break;
case 'g':
stringaArray[i]='J';
break;
case 'h':
stringaArray[i]='K';
break;
case 'i':
stringaArray[i]='L';
break;
case 'j':
stringaArray[i]='M';
break;
case 'k':
stringaArray[i]='N';
break;
case 'l':
stringaArray[i]='O';
break;
case 'm':
stringaArray[i]='P';
break;
case 'n':
stringaArray[i]='Q';
break;
case 'o':
stringaArray[i]='R';
break;
case 'p':
stringaArray[i]='S';
break;
case 'q':
stringaArray[i]='T';
break;
case 'r':
stringaArray[i]='U';
break;
case 's':
stringaArray[i]='V';
break;
case 't':
stringaArray[i]='W';
break;
case 'u':
stringaArray[i]='X';
break;
case 'v':
stringaArray[i]='Y';
break;
case 'w':
stringaArray[i]='Z';
break;
case 'x':
stringaArray[i]='A';
break;
case 'y':
stringaArray[i]='B';
break;
case 'z':
stringaArray[i]='C';
break;
}
}
String encripted= new String(stringaArray);
return encripted;
}
}
Then I use this method in the graphical interface class so that it acts when a button is pressed like this:
private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {
String stringa=messageTxt.getText();
encriptedTxt.setText(Util.Encript(stringa, encriptedTxt));
}
Here is an example of test-case:
Test case:
aBxyE //Input
dEabH //Output
Thank you in advance!
Khoor/#Zruog
You could iterate the characters in the String, and I would also pass in the key offset. Create a StringBuilder and append each character after performing integer addition and casting. Something like,
public static String encrypt(String msg, int key) {
StringBuilder sb = new StringBuilder();
for (char ch : msg.toCharArray()) {
char c = (char) (ch + key);
sb.append(c);
}
return sb.toString();
}
Decryption is trivial with a Caesar cipher; you can call encrypt with the negative value of the key
public static String decrypt(String msg, int key) {
return encrypt(msg, -key);
}
And I tested my example with
public static void main(String[] args) {
String msg = encrypt("Hello, World", 3);
System.out.println(msg);
System.out.println(decrypt(msg, 3));
}
Finally, as others have noted, the Caesar cipher is terribly insecure (because letter frequency is not perturbed, it's trivial in a modern sense).
This code will sawp a char with another one three chars apart, as defined in ALPHABET :
public class Util
{
private final static String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public static String encript(String stringa)
{
char[] stringaArray = stringa.toCharArray();
for (int i =0; i<stringaArray.length; i++) {
char c = stringaArray[i];
int index = ALPHABET.indexOf(c);
if(index <0)
{
continue ; //if c does not appear in ALPHABET
}
// for example c is *, leave it unchanged
if((index +3) >= ALPHABET.length() ) {
index = index - ALPHABET.length();
}
stringaArray[i] = ALPHABET.charAt(index+3);
}
String encripted= new String(stringaArray);
return encripted;
}
}
If it is not clear, do not hesitate to ask.
Here is my Short and Efficient code for your program:
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//N is length of string
int N = Integer.parseInt(br.readLine());
//Reading string Input
String str = br.readLine();
//K is the key to rotate characters in the string
//In your case K = 3
int K = Integer.parseInt(br.readLine());
K %= 26; //Incase K is greater than 25
//Main [tag:algorithm]
for(int i = 0; i < N; i++){
char c = str.charAt(i);
if(c >= 65 && c <= 90){
c += K;
if(c > 90){
c = (char)(c - 90 + 64);
}
}
if(c >= 97 && c <= 122){
c += K;
if(c > 122){
c = (char)(c - 122 + 96);
}
}
System.out.print(c);
}
}
}
I am doing k = k % 26 because if the k = 26 then it will print the same letter, if k = 27 the character will rotate only 1 time and so on.

Categories

Resources