Reverse a string in Java without StringBuilder - java

I am trying to reverse a string WITHOUT using StringBuilder. I have written the below code but it is giving an error as soon as it hits the loop. The error is
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 16
at lectures.ReverseString.main(ReverseString.java:38)
if anyone could tell me why that would be great. FYI I realize this code is not efficient or elegant but I want to know why it isn't working for education.
public static void main(String[] args) {
//declare variables
Scanner input = new Scanner(System.in);
String myString = "";
int length = 0, index = 0, index2 = 0;
//get input string
System.out.print("Enter the string you want to reverse: ");
myString = input.nextLine();
//find length of string
length = myString.length();
index2 = length;
//convert to array
char[] stringChars = myString.toCharArray();
char[] stringChars2 = stringChars;
//loop through and reverse order
while (index<length) {
stringChars2[index] = stringChars[index2];
index++;
index2--;
}
//convert back to string
String newString = new String(stringChars2);
//output result
System.out.println(newString);
//close resources
input.close();
}

The last index in an array is not array.length but array.length - 1. Arrays are indexed on a zero-base, the first index is 0.
An array with two elements for example has indices [0] and [1], not [2].
You access, in the first iteration, stringChars[index2] and index2 = length where length = myString.length(). Thus the IndexOutOfBoundException. Carefully read through your code and analyze which indices you need. Create a small example, use some small print statements to debug your code and see which indices you are actually using.
Here is an example for a more compact reverse algorithm:
char[] input = ...
// Iterate in place, from both sides at one time
int fromFront = 0;
int fromEnd = input.length - 1;
while (fromFront < fromEnd) {
// Swap elements
char temp = input[fromEnd];
input[fromEnd] = input[fromFront];
input[fromFront] = temp;
fromFront++;
fromEnd--;
}
The algorithm swaps the element from the first position with the element from the last position in place. Then it moves one forward swapping the second element with the second to last and so on. It stops once both indices meet each other (if length is odd) or if the first index gets greater then the other (if length is even).
A more easy version, however without in-place, is to create a new array:
char[] input = ...
char[] reversedInput = new char[input.length];
// Reversely iterate through source
int forwardIndex = 0;
for (int i = input.length - 1; i > 0; i--) {
reversedInput[forwardIndex] = input[i];
forwardIndex++;
}

Related

Index out of bound Exception... and sorting is wrong, please check below code, what is the problem?

Index out of bound Exception... and sorting is wrong, please check below code, what is the problem ??
it takes string and an integer as input, it computes all the substrings of length k then sees which substring is lexicographically first and last and sorts it inside collection array and returns lexicographically smallest as smallest and largest as largest
public static String getSmallestAndLargest(String s, int k) {
String smallest = "";
String largest = "";
String[] collections = new String[s.length()-k];
for(int i=0;i<=s.length()-k-1; i++) {
// if(i==(s.length()-k)){
// collections[i] = s.substring(i,i+k-1);
// }
collections[i] = s.substring(i,i+k);
}
for(int i=0; i<collections.length;i++){
System.out.print(collections[i]+" ");
}
System.out.println("");
for(int i=0;i<collections.length-1;i++){
for(int q=1;q<collections.length;q++){
if(collections[i].compareTo(collections[q])<0){
String temp = collections[i];
collections[i]=collections[q];
collections[q]=temp;
}
}
}
smallest = collections[0];
largest = collections[collections.length-1];
for(int i=0; i<collections.length;i++){
System.out.print(collections[i]+" ");
}
System.out.println("");
// s.substring(0,3) , s.substring(3,6) , substring(i,i+k)
return smallest + "\n" + largest;
}
Your array size is to small. For Example: if your string is 6 characters long and the substring length k would be 5, your array should fit 2 strings inside.
To compensate for the too small array you reduced the loop also by 1, effectively ignoring the last substring.
Whatever sorting-algorithm you tried to implement made little sense. If you want to implement the sorting yourself, have a look here. If you're fine with using java sorting the array for you, use Collections.sort() which takes the array in form of a list.
Additional Note: uppercase characters have a lower index
The fixed code would look like this:
public static String getSmallestAndLargest(String s, int k) {
String smallest = "";
String largest = "";
//1. create an array with the length of possible substrings
String[] collections = new String[s.length() - k + 1];
//2. fill the array with these substrings
for (int i = 0; i <= s.length() - k; i++) {
collections[i] = s.substring(i, i + k);
}
//print all substrings in original order
for (int i = 0; i < collections.length; i++) {
System.out.print(collections[i] + " ");
}
System.out.println("");
//3. sort the array
Collections.sort(Arrays.asList(collections));
smallest = collections[0];
largest = collections[collections.length - 1];
//print in sorted order
for (int i = 0; i < collections.length; i++) {
System.out.print(collections[i] + " ");
}
System.out.println("");
return smallest + "\n" + largest;
}
If you're asking a question you should also provide context and examples for your inputs, the expected outputs and the whole Stacktrace if there is one. That way other people don't need to reproduce the error themselves to help you. Also formatting and commenting your code helps a lot.

Is there a way to initialize a 2d array with other arrays?

I have been given a homework assignment as follows:
Read three sentences from the console application. Each sentence should not exceed 80 characters. Then, copy each character in each input sentence in a [3 x 80] character array.
The first sentence should be loaded into the first row in the reverse order of characters – for example, “mary had a little lamb” should be loaded into the array as “bmal elttil a dah yram”.
The second sentence should be loaded into the second row in the reverse order of words – for example, “mary had a little lamb” should be loaded into the array as “lamb little a had mary”.
The third sentence should be loaded into the third row where if the index of the array is divisible by 5, then the corresponding character is replaced by the letter ‘z’ – for example, “mary had a little lamb” should be loaded into the array as “mary zad azlittze lazb” – that is, characters in index
positions 5, 10, 15, and 20 were replaced by ‘z’. Note that an empty space is also a character, and that the index starts from position 0.
Now print the contents of the character array on the console.
The methods, return types, and parameters in the code below are all specified as required so I cannot change any of that information. I am having trouble initializing the 2d array. The instructions say that the sentences must be loaded into the array already reversed etc. but the parameters of the methods for doing this calls for strings. I assume that means I should read the lines as strings and then call the methods to modify them, then use toCharyArray to convert them before loading them into the 2d array. I don't understand how to initialize the 2D array with the values of the char arrays. Is there some kind of for loop I can use? Another issue is that no processing can be done inside of the main method but in the instructions there is no method that I can call to fill the array.
import java.util.regex.Pattern;
public class ReversedSentence {
public static String change5thPosition(String s){
char[] chars = s.toCharArray();
for (int i = 5; i < s.length(); i = i + 5) {
chars[i] = 'z';
}
String newString = new String(chars);
return newString;
}
public static String printChar2DArray(char[][] arr){
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 80; y++) {
// just a print so it does not make new lines for every char
System.out.print(arr[x][y]);
}
}
return null;
}
public static String reverseByCharacter(String s){
String reverse = new StringBuffer(s).reverse().toString();
return reverse;
}
public static String reverseByWord(String s){
Pattern pattern = Pattern.compile("\\s"); //splitting the string whenever there
String[] temp = pattern.split(s); // is whitespace and store in temp array.
String result = "";
for (int i = 0; i < temp.length; i++) {
if (i == temp.length - 1)
result = temp[i] + result;
else
result = " " + temp[i] + result;
}
return result;
}
public static String truncateSentence(String s){
if (s==null || s.length() <= 80)
return s;
int space = s.lastIndexOf(' ', 80);
if (space < 0)
return s.substring(0, 80);
return s;
}
public static void main(String[] args) {
String sentence1 = ("No one was available, so I went to the movies alone.");
String sentence2 = "Ever since I started working out, I am so tired.";
String sentence3 = "I have two dogs and they are both equally cute.";
char[][] arr = new char[3][80];
arr[0] = reverseByCharacter(sentence1).toCharArray();
arr[1] = reverseByWord(sentence2).toCharArray();
arr[2] = change5thPosition(sentence3).toCharArray();
printChar2DArray(arr);
}
}
The error I am getting is:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 52 out of bounds for length 52
at ReversedSentence.printChar2DArray(ReversedSentence.java:20)
at ReversedSentence.main(ReversedSentence.java:71)
.enola seivom eht ot tnew I os ,elbaliava saw eno oN
The problem is that in your printChar2DArray method you assume that every array has the length of 80, but that's actually not the case here. In Java, a 2D array is just an array of arrays. So, when you have this: char[][] arr = new char[3][80], you are creating an array of 3 arrays, and each of these arrays has the length of 80 characters. That may seem ok, but in the next lines you reinitialize the 3 arrays with something different entirely.
arr[0] = reverseByCharacter(sentence1).toCharArray();
arr[1] = reverseByWord(sentence2).toCharArray();
arr[2] = change5thPosition(sentence3).toCharArray();
Now none of these arrays has the length of 80. Each of them has the length of the respective string.
You can solve this in 2 ways (depending on how constrained your task actually is).
First, you can copy the string into arrays, instead of assigning the arrays to the results of the toCharArray method. You can achieve this with a simple loop, but I wouldn't recommend this approach, because you will end up with arrays of 80 characters, even if the strings contain less.
String firstSentence = reverseByCharacter(sentence1);
for (int i = 0; i < firstSentence.length(); i++) {
arr[0][i] = firstSentence.charAt(i);
}
Or:
char[] firstSentence = reverseByCharacter(sentence1).toCharArray();
for (int i = 0; i < firstSentence.length; i++) {
arr[0][i] = firstSentence[i];
}
Second, you can drop the assumption of the arrays' lengths in the printChar2DArray method. I recommend this approach, because it makes you code much more flexible. Your printChar2DArray method will then look like this:
public static String printChar2DArray(char[][] arr){
for (int x = 0; x < arr.length; x++) {
for (int y = 0; y < arr[x].length; y++) {
// just a print so it does not make new lines for every char
System.out.print(arr[x][y]);
}
}
return null;
}
You can see that I've substituted numbers with the length field, which can be accessed for any array.
Also, this way you don't need to initialize the inner arrays, because you reinitialize them in the next lines anyway.
char[][] arr = new char[3][];
arr[0] = reverseByCharacter(sentence1).toCharArray();
arr[1] = reverseByWord(sentence2).toCharArray();
arr[2] = change5thPosition(sentence3).toCharArray();
But this approach may not be suitable for your task, because then the sentences could be of any length, and they wouldn't be constained to 80 characters max.
UPDATE - To answer the question in the comment
To print a newline character you can use System.out.println() without parameters. It's better than putting the newline character into the arrays because it's not a logical part of the sentences.
So your for-loop in the printChar2DArray would look like this:
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 80; y++) {
// just a print so it does not make new lines for every char
System.out.print(arr[x][y]);
}
System.out.println();
}

Storing Reverse String in 2D Array

I am trying to get the contents of a string, and store it in the last row of my 2D array here is what I have so far:
char[][] square = new char[5][5];
String number = new String("three");
for(int k = number.length() - 1; k >= 0; k--)
{
square[4][k] = number.charAt(k);
}
The output the code is giving me is the string in non reversed order.
Isn't this the logic for reversing a string? All I am doing here is setting the fourth column, and all rows starting at the end of the string to it's value. What am I missing?
Thanks
just walk through the loop by hand.
The first time through, k is 4.
So, square[4][4] is set to the character returned by .charAt(4), which is an 'e'.
then square[4][3] becomes 'e', ... and square[4][0] becomes 't'.
square[4] now reads t,h,r,e,e.
You've basically reversed both ends. Try this:
for (int k = 0; k < number.length(); k++) {
square[4][k] = number.charAt(number.length() - k - 1);
}
Yes, because you're not reversing it. You're setting the same character back again at the same position. If you need it reversed then the logic should be
square[4][number.length() - (k + 1)] = number.charAt(k);
You need a different index beyond square[4][k] when you are also copying the value from number.charAt(k) - that is, you are copying the characters backwards (but into the array also backward). There is no need to call new String(String). You could do
char[][] square = new char[5][5];
String number = "three";
for (int i = 0; i < number.length(); i++) {
int k = number.length() - i - 1;
square[4][k] = number.charAt(i);
}
But I would prefer a StringBuilder and StringBuilder.reverse() myself. Like,
char[][] square = new char[5][5];
String number = "three";
square[4] = new StringBuilder(number).reverse().toString().toCharArray();

How to determine ASCII value of a word

I am creating a program that imports a large list of words. This list has been separated by word but I now need to determine the ASCII value of each word in this list, and eventually which one has the highest total ASCII value. I am receiving a few errors and need to know how to get this corrected so that I can get each value.
public static void main(String[] args) throws IOException {
//import list of words
BufferedReader File = new BufferedReader(new FileReader(LOC));
//Create a temporary ArrayList to store data
ArrayList<String> words = new ArrayList<String>();
//Find number of lines in txt file
String line;
String delimiter = "\t";
while ((line = File.readLine()) != null)
//read the file
{
String[] wordsInLine = line.split(delimiter);
//separate the words
for(int i=0, isize = wordsInLine.length; i < isize; i++){
words.add(wordsInLine[i]);//put them in a list
//assess each character in the word to determine the ascii value
int total = 0;
for (int i=0; i < wordsInLine.length(); i++)
Receiving an error on the above line that states - Cannot invoke length() on the array type
String[]
- Duplicate local variable i
{
char c = word.charAt(i);
Receiving an error on the above line that states word cannot be resolved
int j = (int) c;
total += c;
}
I have done some research trying to determine the best way to calculate the ASCII value of each word and I haven't been able to find much information on how to do this. If someone could please take a look at my code I would appreciate it!! Also, before anyone says it let me just say this is NOT a school project. I am on summer break and beginning programming II in the fall and just trying to keep up on coding so that I am not rusty in the fall. THANK YOU!!! :))
Receiving an error on the above line that states - Cannot invoke length() on the array type String[] - Duplicate local variable i
wordsInLine is an array, and length is property of array. So, you have to use:
wordsInLine.length
If wordsInLine was a String, then wordsInLine.length() would have made sense.
Receiving an error on the above line that states word cannot be resolved
Before the line char c = word.charAt(i);, add below:
String word = wordsInLine[i];
For the wordsInLine.length() issue, length() is not a valid method for arrays. You actually have to access the length field thusly: wordsInLine.length without ().
As for word.charAt(i), you haven't declared a variable called word anywhere which is what's causing the problem. What you really want to do is sum up the values for every word in the array, and for that you need a nested loop.
You also said that you wanted to figure out which one had the highest value. To do that, just keep track of the largest one and update it after each iteration like this:
int indexOfMax = 0;
int[] sums = new int[wordsInLine.length];
//Iterate over every word
for(int i = 0; i < wordsInLine.length; i++)
{
//Reset the total for each word
total = 0;
//Iterate over every character in the word
for(int j = 0; j < wordsInLine[i].length(); j++)
{
char c = wordsInLine[i].charAt(j);
total += c;
}
//Remember the sum for this word
sums[i] = total;
//If the word's sum is greater than our previous max,
//make it the new max
if(sums[i] > sums[indexOfMax])
{
indexOfMax = i;
}
}
And now you can get the word with the greatest ASCII value by calling wordsInLine[indexOfMax]. It will have an ASCII sum of sums[indexOfMax].
wordsInLine is an array and therefore it does not have a method to get its length. Instead, to get an array's length, use array.length as opposed to what you were doing: array.length() (which causes an error).
word is not a defined variable, this is why java is saying that it cannot be resolved (it can't find any declaration). Instead you want to use 2 for loops in order to loop over every character in the word in the array wordsInLine. You also have two instances of the variable i, this is not allowed. To fix these errors write the following code after `int total = 0;':
int total = 0; // Don't rewrite this line
int[] totals = new int[wordsInLine.length]; // If you want to add all your totals to an array
for (int j=0; j < wordsInLine.length; j++) {
total = 0;
for (int k=0; k < wordsInLine[j].length(); k++) { // Here wordsInLine[j] is a string so you use .length() instead of .length
char c = wordsInLine[j].charAt(k);
int w = (int) c; // Get ascii of c
total += w; // Add it to total
}
// Do something with the total of this word before it gets reset to 0
// Maybe add it to an array of totals:
totals[j] = total;
}
I hope this helps!
Well your organization of your code needs a little bit of work.
First I would take this whole block of code outside file read in while loop.
for (int i=0; i < wordsInLine.length(); i++)
{
char c = word.charAt(i);
int j = (int) c;
total += c;
}
Why? Lets split what you are doing into two steps. Read in all the words into the word list. After doing this you will find where your core root of the problem is. You aren't reading the words from your word list at all.
Further code cleanup
for(int i=0, isize = wordsInLine.length; i < isize; i++){
This line is a little bit bloated. You don't need isize at all you are essentially doing denoting it for no reason. (Well actually caching the length does improve efficiency, another talk for another day). Cleaning up.
for(int i=0, ; i < wordsInLine.length; i++){
Then fixing the entire project
//import list of words
BufferedReader File = new BufferedReader(new FileReader(LOC));
//Create a temporary ArrayList to store data
ArrayList<String> words = new ArrayList<String>();
//Find number of lines in txt file
String line;
String delimiter = "\t";
// adds all the words into the list.
while ((line = File.readLine()) != null)
{
String[] wordsInLine = line.split(delimiter);
for(int i=0, ; i < wordsInLine.length; i++){
// compute alg and store the value some how to the word.
words.add(wordsInLine[i])
}
}
// notice outside the while loop.
// .size() is used for lists and .length is used for arrays.
for(int i = 0; i < words.size(); i++){
// compare
}

2d char array from a file

I am trying to read in a string from a file, extract individual characters and use those characters to fill a 2D char array. So far I have been able to do everything except fill the array. I keep getting an Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: error message. Any help would be appreciated. This is my first time working with 2D arrays. Thanks.
Here are the contents of the test.txt. Each word on a new line. The first 2 integers are the dimensions of the array
4 4
FILE
WITH
SOME
INFO
public class acsiiArt
{
public static void main(String[] args) throws IOException
{
File file = new File("test.txt");
Scanner inputFile = new Scanner(file);
int x = inputFile.nextInt();
int y = inputFile.nextInt();
while (inputFile.hasNext())
{
char [][] array = new char [x][y];
//char c = words.charAt(i);
for (int row =0; row<x;row++)
{
for (int col =0; col<y;col++)
{
String words = inputFile.nextLine();
for (int i=0; i<words.length(); i++)
array[x][y]=words.charAt(i);
}
}
}
}
}
for (int row =0; row<x;row++)
{
for (int col =0; col<y;col++)
{
String words = inputFile.nextLine();
for (int i=0; i<words.length(); i++)
array[x][y]=words.charAt(i);
}
}
The total number of indices in array is x * y. Below, you are filling all the possible indices
for (int row =0; row<x;row++)
{
for (int col =0; col<y;col++)
So when you add this:
for (int i=0; i<words.length(); i++)
you multiplying another factor words.length. So you need x * y * words.length number of indices, but you only have x * y. Thats why you're getting ArrayIndexOutOfBoudsException
I've seen problems like this and I'm assuming that x and y are being initialized to the first two characters which represent the number of rows and the number of columns. If that is the case, then third for loop for (int i=0; i<words.length(); i++) is unnecessary. You can just reffer to the col variable for the word at that point, since it should represent how many characters there are.
All of this is only applicable if the chars are in a rectangular pattern, meaning that there are the same number of columns in every row. Otherwise you will get an IndexOutOfBoundsError as soon as one of the lines is shorter than the the column value initially given.
Edit: If you're final 2d char array is not meant to be rectangular and instead "jagged," a different implementation is required. I'd recommend either a 2d arrayList (an arrayList of arrayLists).
Or you can keep your current implementation with the third for loop, but you have to be sure that the original x value represents the longest row/most amount of columns, and then you'd be able to deal with each row indivually with words.length. You'd also have to be fine with the extra portions of the lines that have a length>x having spaces initialized to null.
ArrayIndexOutOfBoundsException means you are using array beyond its limit. So in your case:
char [][] array = new char [x][y];
//char c = words.charAt(i);
for (int row =0; row<x;row++) {
for (int col =0; col<y;col++){
String words = inputFile.nextLine();
for (int i=0; i<words.length(); i++)
array[x][y]=words.charAt(i);
}
}
Problem may be because your array size is less then input words. problem is because you are putting extra loop, and your loop it self is not correct. Please seen code below.
So you can do 2 things.
change value of y large enough so that any word string can store.
rather than looping on size of word you can loop on your array size like.
.
for (int row =0; row<x;row++) {
String words = inputFile.nextLine();
int size = Math.min(words.length(),y);
for (int i=0; i< size; i++)
array[row][i]=words.charAt(i);
}
The easiest way to do this is with an ArrayList<char[]>. All you have to do is add a new char[] for each new line read:
ArrayList<char[]> chars = new ArrayList<>();
while (inputFile.hasNext()){
chars.add(inputFile.nextLine().toCharArray());
}
char[][] array = chars.toArray(new char[chars.size()][]);
An ArrayList is basically an array of changeable size. This code takes each line in the file, turns it into a char[], then adds it to the ArrayList. At the end, it converts the ArrayList<char[]> into a char[][].
If you can't or don't want to use ArrayList, you could always do this:
char[][] array = new char[1][];
int a = 0;
while(inputFile.hasNext()){
//read line and convert to char[]; store it.
array[a] = inputFile.nextLine().toCharArray();
//if there are more lines, increment the size of the array.
if (inputFile.hasNext()){
//create a clone array of the same length.
char[][] clone = new char[array.length][];
//copy elements from the array to the clone. Note that this can be
//done by index with a for loop
System.arraycopy(array, 0, clone, 0, array.length);
//make array a new array with an extra char[]
array = new char[array.length + 1][];
//copy elements back.
System.arraycopy(clone, 0, array, 0, clone.length);
a++;
}
}
If you know the dimensions of the array beforehand:
char[][] array = new char[dimension_1][];
int a = 0;
while (inputFile.hasNext()){
array[a] = inputFile.nextLine().toCharArray();
a++; //don't need to check if we need to add a new char[]
}
In response to comment:
We know that a char[][] cannot be printed with Arrays.toString() (if we want the contents) because we will get a lot of char[].toString(). However, a char[][] can be printed with one of the following methods:
public static String toString(char[][] array){
String toReturn = "[\n";
for (char[] cArray: array){
for (char c: cArray){
toReturn += c + ",";
}
toReturn += "\n";
}
return toReturn + "]";
}
I personally prefer this one (requires import java.util.Arrays):
public static String toString(char[][] array){
String toReturn = "[\n";
for (char[] cArray: array){
toReturn += Arrays.toString(cArray) + "\n";
}
return toReturn + "]";
}

Categories

Resources