What is the most efficient way to reverse a char array? - java

I tried two different ways to reverse a char array
//method 1
char c[] = {'A', 'B', 'C', 'D'};
char c_rev[] = new char[4];
for (int i = 3; i >= 0; i--) {
c_rev[i] = c[3 - i];
}
System.out.println(Arrays.toString(c_rev));
//method 2
char c[] = {'A', 'B', 'C', 'D'};
Stack<Character> st = new Stack();
for (int i = 0; i < 4; i++) {
st.push(c[i]);
}
for (int i = 0; i < 4; i++) {
c[i] = st.pop();
}
System.out.println(Arrays.toString(c));
I just wondered what will be the most efficient one. Method 1 or Method 2 ?
Can anyone help me or give any suggestions ?

In terms of time complexity, they're both O(n). Performance wouldn't be significant here.
Which to choose? None. I would use a ready method StringBuilder#reverse:
String reversed = new StringBuilder(new String(c)).reverse().toString();
If I wanted to choose one from the two methods you posed, I would have choose the first one, it have only one loop and it's straightforward, no methods will be called, no helper objects will be created; you simply create a new array and directly push to it the new elements.

#MarounMaroun's answer will work for char arrays that are really strings. If you are worried only about those two methods then the first involves less heap allocations and GC.
However in general for an array I would use neither of your methods, but instead:
int len = c.length;
for(int i = 0; i < len / 2; i++) {
char ch = c[i];
c[i] = c[len - i - 1];
c[len - i - 1] = ch;
}
It is:
shorter to type than method 2
only iterates for half the array length (it is still O(n) due to the ops per iteration)
will work for any array type
doesn't need extra object allocations (vs Method 2) or two arrays (vs Method 1)
I would, however, be careful of micro-optimizations like this. The difference between this and Method 1 is probably minimal for small array allocations so you are better off using the one that is easiest for you to understand. (Similarly I only pulled the len variable out for clarity - some microbenchmarks claim it speeds up loops, but the downside is it pollutes your local variables with something that is only used inside the loop).

I'd say that method 1 is probably faster since it doesn't require the creation, allocation, and destruction of new objects (i.e. the Stack and its internal objects). For the same reason it should also have a lower impact on the garbage collector.
If this is a frequent operation in your code, you can benchmark both methods using something like Google caliper. Otherwise, I wouldn't worry about it :)

Logical operators works more efficiently than using a method of assignment operators (swapping) using third variable:
public static char[] reverseArray(char[] array) {
for(int i=0; i<array.length/2; i++)
{
array[i]^=array[array.length-i-1];
array[array.length-i-1]^=array[i];
array[i]^=array[array.length-i-1];
}
return array;
}
public static void main(String[] args) {
char[] input = {'H','e','l','l','o'};
System.out.println(reverseArray(input));
char[] input2 = {'J','a','v','a'};
System.out.println(reverseArray(input2));
}

Related

Why does using arrays instead of string give less memory consumption and time executing?

Given the string in the form of char array. Modify it the way that all the exclamation point symbols '!' are shifted to the start of the array, and all ohters are in the same order. Please write a method with a single argument of type char[]. Focus on either memory and time consumption of alghoritm.
Feedback that i've received: it was possible to use working with arrays instead of strings. Where can i find info about memory?
public static String formatString(char[] chars) {
StringBuilder exclamationSymbols = new StringBuilder();
StringBuilder otherSymbols = new StringBuilder();
for (char c : chars) {
if (c == '!') {
exclamationSymbols.append(c);
} else {
otherSymbols.append(c);
}
}
return (exclamationSymbols.toString() + otherSymbols.toString());
}
You can do this faster using a char[] than a StringBuilder because:
a StringBuilder is just a wrapper around a char[], so there's no way it can be faster. The indirection means it will be slower.
you know exactly how long the result will be, so you can allocate the minimum-sized char[] that you'll need. With a StringBuilder, you can pre-size it, but with two StringBuilders you can't exactly, so you either have to over-allocate the length (e.g. make both the same length as chars) or rely on StringBuilder resizing itself internally (which will be slower than not; and it uses moer memory).
My idea would be to use two integer pointers to point to the next position that you'll write a char to in the string: one starts at the start of the array, the other starts at the end; as you work your way through the input, the two pointers will move closer together.
Once you've processed the entire input, the portion of the result array corresponding to the "end pointer" will be backwards, so reverse it.
You can do it like this:
char[] newChars = new char[chars.length];
int left = 0;
int right = chars.length;
for (char c : chars) {
if (c == '!') {
newChars[left++] = c;
} else {
newChars[--right] = c;
}
}
// Reverse the "otherSymbols".
for (int i = right, j = newChars.length - 1; i < j; ++i, --j) {
char tmp = newChars[i];
newChars[i] = newChars[j];
newChars[j] = tmp;
}
return new String(newChars);
Ideone demo

Why is the second code more efficient than the first one?

I am confused between two codes, why the second one I am going to give here is more efficient than the first one.
Both of the codes just reverse a String, but first code is slower than the other and I am not able to understand why.
The first code is:
String reverse1(String s) {
String answer = "";
for(int j = s.length() - 1; j >= 0; j--) {
answer += s.charAt(j);
}
return answer;
}
The second code is:
String reverse2(String s) {
char answer[] = new char[s.length()];
for(int j = s.length() - 1; j >= 0; j--) {
answer[s.length() - j - 1] = s.charAt(j);
}
return new String(answer);
}
And I'm not able to understand how the second code is more efficient than the first one, I'd appreciate any insight on this.
The first code declares
String answer;
Strings are immutable. Therefore, every append operation reallocates the entire string, copies it, then copies in the new character.
The second code declares
char answer[];
Arrays are mutable, so each iteration copies only a single character. The final string is created once, not once per iteration of the loop.
Your question is perhaps difficult to answer exactly, in part because the answer would depend on the actual implementation of the first version. This, in turn, would depend on what version of Java you are using, and what the compiler decided to do.
Assuming that the compiler keeps the first version verbatim as you wrote it, then yes, the first version might be more inefficient, because it would require allocating a new string for each step in the reversal process. The second version, on the contrary, just maintains a single array of characters.
However, if the compiler is smart enough to use a StringBuilder, then the answer changes. Consider the following first version:
String reverse1(String s) {
StringBuilder answer = new StringBuilder();
for (int j = s.length() - 1; j >= 0; j--)
answer.append(s.charAt(j));
return answer;
}
Under the hood, StringBuilder is implemented using a character array. So calling StringBuilder#append is somewhat similar to the second version, i.e. it just adds new characters to the end of the buffer.
So, if your first version executes using literal String, then it is more inefficient than the second version, but using StringBuilder it might be on par with the second version.
String is immutable. Whenever you do answer += s.charAt(j); it creates a new object. Try printing GC logs using -XX:+PrintGCDetails and see if the latency is caused by minor GC.
String object is immutable and every time you made an add operation you create another object, allocating space and so on, so it's quite inefficient when you need to concatenate many strings.
Your char array method fits your specific need well, but if you need more generic string concatenation support, you could consider StringBuilder
In this code you are creating a new String object in each loop iteration,because String is immutable class
String reverse1(String s) {
String answer = "";
for (int j = s.length() - 1; j >= 0; j--)
answer += s.charAt(j);
return answer;
}
In this code you have already allocated memory to char array,Your code will create only single String at last line, so it is more efficient
String reverse2(String s) {
char answer[] = new char[s.length()];
for (int j = s.length() - 1; j >= 0; j--)
answer[s.length() - j - 1] = s.charAt(j);
return new String(answer);
}
Why is the second code more efficient than the first one?
String is immuable, by answer += s.charAt(j); you are creating a new instance of String in each loop, which makes your code slow.
Instead of String, you are suggested to use StringBuilder in a single thread context, for both performance and readablity(might be a little slower than fix-sized char array but has a better readablity):
String reverse1(String s) {
StringBuilder answer = new StringBuilder("");
for (int j = s.length() - 1; j >= 0; j--)
answer.append(s.charAt(j));
return answer.toString();
}
The JVM treats strings as immutable. Hence, every time you append to the existing string, you are actually create a new string! This means that a new string object has to be created in heap for every loop iteration. Creating an object and maintaining its lifecycle has its overhead. Add to that the garbage collection of the discarded strings (the string created in the previous iteration won't have a reference to it in the next, and hence, it is collected by the JVM).
You should consider using a StringBuilder. I ran some tests and the time taken by the StringBuilder code is not much smaller than that of the fixed-length array.
There are some nuances to how the JVM treats strings. There are things like string interning that the JVM does so that it does not have to create a new object for multiple strings with the same content. You might want to look into that.

multiply string element per int element from two arrays Java

I am learning Java and looking for a comprehensive code of multiplying the elements from 2 arrays, possibly without importing anything to achieve it.
In Python it's quite easy:
a=['a','b','c','d']
b=[1,2,3,4]
[x*y for x,y in zip(a,b)]
['a', 'bb', 'ccc', 'dddd']
How can I achieve the same thing in Java, when the first array is an array of strings and the second is integers?
I'm afraid Java isn't going to support this kind of thing natively, and you'll need to perform some of your own logic to implement it. Let's say you've got your String[]..
String[] a = {"a", "b", "c", "d"};
And you've got your int[]..
int[] b = {1,2,3,4};
Next, you'll need to check that the arrays are the same size.
if(a.length == b.length) {
// Continue.
}
Then you need to implement a loop, to go through each item in the arrays.
for(int x = 0; x < a.length; x++)
{
// Some looping code.
}
And you're going to grab each item.
String value = a[x];
int multiplier = b[x];
If you're not importing anything, you declare the total value:
String total = "";
But if you're allowing for a StringBuilder, then you'll import it and declare..
StringBuilder total = new StringBuilder();
NOTE: StringBuilder is strongly recommended here.
And then you're looping multiplier amount of times..
for(int y = 0; y < multiplier; y++)
{
// If you use StringBuilder..
total.append(value);
// If you don't..
total += value;
}
// If you use StringBuilder..
a[x] = total.toString();
// If you don't...
a[x] = total;
This will set the value of a[x] to the repeated String.
NOTE: Something that's also important is leaning good practise. If you're using Java code, it's considered terrible practise to repeatedly concatenate String objects. StringBuilder is more efficient, and is the Java standard. I would strongly recommend using this.
Have fun putting it all together!!
To create string filled with multiple instances of same character like "ccc" you can firs create array of characters which will hold only 3 characters like
char[] myCharacters = new char[3];
Now this array is filled with zeroes ('\0'), so you need to fill it with desired character 'c'. You simply do it using for loop
for (int i = 0; i<myCharacters; i++){
myCharacters[i] = 'c';
}
After this your array will contain ['c', 'c', 'c'].
Now you can use this array to create string using characters from it. To do so you just need to pass this array to String constructor like
String myString = new String(myCharacters);
And there you go. Now you have "ccc" String. Repeat these steps for each pair of elements from a and b arrays.
You can also use shorter version which kinds of do the same
String myString = new String(new char[3]).replace('\0','c');//will produce "ccc"

Why will this java string routine not print the answer?

I have been working on the Project Euler problem 4. I am new to java, and believe I have found the answer (906609 = 993 * 913, by using Excel!).
When I print the line commented out, I can that my string manipulations have worked. I've researched a few ways to compare strings in case I had not understoof something, but this routine doesn't give me a result.
Please help me identify why it is not printing the answer?
James
public class pall{
public static void main(String[] args){
int i;
int j;
long k;
String stringProd;
for(i=994;i>992; i--){
for (j=914;j>912; j--){
k=(i*j);
stringProd=String.valueOf(k);
int len=stringProd.length();
char[] forwards=new char[len];
char[] back = new char[len];
for(int l=0; l<len; l++){
forwards[l]=stringProd.charAt(l);
}
for(int m=0; m<len;m++){
back[m]=forwards[len-1-m];
}
//System.out.println(forwards);
//System.out.println(back);
if(forwards.toString().equals(back.toString())){
System.out.println(k);}
}
}
}
}
You are comparing the string representation of your array. toString() doesn't give you what you think. For example, the below code makes it clear:
char[] arr1 = {'a', 'b'};
char[] arr2 = {'a', 'b'};
System.out.println(arr1.toString() + " : " + arr2.toString());
this code prints:
[C#16f0472 : [C#18d107f
So, the string representation of both the arrays are different, even though the contents are equal. This is because arrays don't override toString() method. It inherits the Object#toString() method.
The toString method for class Object returns a string consisting of
the name of the class of which the object is an instance, the at-sign
character #, and the unsigned hexadecimal representation of the hash
code of the object. In other words, this method returns a string equal
to the value of:
getClass().getName() + '#' + Integer.toHexString(hashCode())
So, in the above output, [C is the output of char[].class.getName(), and 18d107f is the hashcode.
You can't also compare the arrays using forward.equals(back), as arrays in Java don't override equals() or hashCode() either. Any options? Yes, for comparing arrays you can use Arrays#equals(char[], char[]) method:
if (Arrays.equals(forward, back)) {
System.out.println(k);
}
Also, to get your char arrays, you don't need those loops. You can use String#toCharArray() method. And also to get the reverse of the String, you can wrap the string in a StringBuilder instance, and use it's reverse() method:
char[] forwards = stringProd.toCharArray();
char[] back = new StringBuilder(stringPod).reverse().toString().toCharArray();
And now that you have found out an easy way to reverse a string, then how about using String#equals() method directly, and resist creating those character arrays?
String stringPod = String.valueOf(k);
String reverseStringPod = new StringBuilder(stringPod).reverse().toString()
if (stringPod.equals(reverseStringPod)) {
System.out.println(k);
}
Finally, since it is about project euler, which is about speed and mostly mathematics. You should consider avoiding String utilities, and do it with general division and modulus arithmetic, to get each individual digits, from beginning and end, and compare them.
To convert a string to char[] use
char[] forward = stringProd.toCharArray();
To convert a char[] to String, use String(char[]) constructor:
String backStr = new String(back); // Not the same as back.toString()
However, this is not the most performant solution, for several reasons:
You do not need to construct a back array to check if a string is a palindrome - you can walk the string from both ends, comparing the characters as you go, until you either find a difference or your indexes meet in the middle.
Rather than constructing a new array in a loop, you could reuse the same array - in case you do want to continue with an array, you could allocate it once for the maximum length of the product k, and use it in all iterations of your loop.
You do not need to convert a number to string in order to check if it is a palindrome - you can get its digits by repeatedly taking the remainder of division by ten, and then dividing by ten to go to the next digit.
Here is an illustration of the last point:
boolean isPalindrome(int n) {
int[] digits = new int[10];
if (n < 0) n = -n;
int len = 0;
while (n != 0) {
digits[len++] = n % 10;
n /= 10;
}
// Start two indexes from the opposite sides
int left = 0, right = len-1;
// Loop until they meet in the middle
while (left < right) {
if (digits[left++] != digits[right--]) {
return false;
}
}
return true;
}

Which approach is better and optimized between two of the following?

Below are the two approaches for reversing the string with calling API methods. Please tell which approach is better with due justification
public String functionOne(String str){
char arr[] = str.toCharArray();
int limit = arr.length/2;
for (int i = arr.length-1, j = 0; j < limit; i--, j++) {
char c = arr[i];
arr[i] = arr[j];
arr[j] = c;
}
return new String(arr);
}
public String functionTwo(String str) {
StringBuilder strBuilder = new StringBuilder();
char[] strChars = str.toCharArray();
for (int i = strChars.length - 1; i >= 0; i--) {
strBuilder.append(strChars[i]);
}
return strBuilder.toString();
}
Actually when I run my code on string of length 100000, approach second took double time as that of first approach. By using System.currentTimeMillis() I found execution difference of 1 in first approach and 2 in second approach.
How about this:
new StringBuilder("some string").reverse().toString();
The API already in place for this will likely use the most efficient manner.
Second is more readable: I can skim through that without having to think about what it's doing. I would go with that every time (unless there's a good reason why you need it to be milliseconds quicker?)
The first one stops my brain for a few seconds. That means it's dangerous and can easily be broken by future changes. It either needs comments, or replacing (with the second one).
Both are equally same. First is using n/2 operation which is O(n) and the second one is doing it in n operation which is also of O(n) time complexity.
In practice both will run almost equally well because n or n/2 operation won't make much difference.
EDIT: If you don't get the time complexity meaning, try generating a random string of large length say 1 million and calculate the time for both approach.

Categories