Fastest Way To Reverse Long Java [duplicate] - java

This question already has answers here:
Reverse a string in Java
(36 answers)
how to reverse an inputted number [duplicate]
(3 answers)
Closed 2 years ago.
What's the fastest way to reverse a Long value?
For example, 9876543210 should return 0123456789.
This is what I have right now:
long n = 0, c = 987654321 * 10; // *10 is to get 9876543210 as long value;
while (c > 0) n = n * 10 + c % 10;
System.out.println(n);

Your program encounters an infinite loop because you never change the value of c. Add c /= 10 at the end of each iteration and it will work, albeit the leading zero will be dropped due to it being a number.
long n = 0, c = 9876543210L;
while (c > 0){
n = n * 10 + c % 10;
c /= 10;
}
System.out.println(n);
If you need to have the leading zero, you should consider using Strings instead.
long c = 9876543210L;
final StringBuilder sb = new StringBuilder();
while (c > 0){
sb.append(c % 10);
c /= 10;
}
System.out.println(sb.toString());

I think this can be fast
long x = 1234567890L;
String reversed = new StringBuilder(Long.toString(x)).reverse().toString();
// reversed = "0987654321"
If You want to convert a reversed value to a long again:
long x = -1234567890000L;
StringBuilder reversed = new StringBuilder(Long.toString(x)).reverse();
System.out.println(reversed); // 0000987654321-
if (reversed.charAt(reversed.length() - 1) == '-') //remove `-` at last position
{
reversed.setLength(reversed.length() - 1);
}
while (reversed.charAt(0) == '0') //remove all `0` at the beginning
{
reversed.replace(0, 1, "");
}
System.out.println(reversed); // 987654321
long newLong = Long.parseLong(reversed.toString());

You can simply convert to string and then revert the String, in particular if you want string output in the end anyway. This should be quite straight forward and it has the leading 0, it might also be faster than doing calculations for each positions (but the cost of conversion in valueOf might cancel that advantage):
long c = 9876543210L;
String cAsString = String.valueOf(c);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < cAsString.length(); i++) {
builder.append(cAsString.substring(cAsString.length() - (i + 1), cAsString.length() - i));
}
System.out.println(builder.toString());
or as a one liner
long c = 9876543210L;
String reverted = new StringBuilder(String.valueOf(c)).reverse().toString();
System.out.println(reverted);
I did a little comparison between the options of the current answers:
public static void main(String[] args) {
Instant start = Instant.now();
for (long i = 0; i < 100_000_000; i++) {
stringbuilderWithDirectCalcs(i);
}
Duration duration = Duration.between(start, Instant.now());
System.out.println("Took " + duration);
}
protected static void stringbuilderWithDirectCalcs(long value) {
final StringBuilder sb = new StringBuilder();
while (value > 0) {
sb.append(value % 10);
value /= 10;
}
// System.out.println(sb.toString());
}
protected static void stringbuilderConvenient(long value) {
String reverted = new StringBuilder(String.valueOf(value)).reverse().toString();
//System.out.println(reverted);
}
protected static void stringbuilderHandCrafted(long value) {
String cAsString = String.valueOf(value);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < cAsString.length(); i++) {
builder.append(cAsString.substring(cAsString.length() - (i + 1), cAsString.length() - i));
}
//System.out.println(builder.toString());
}
I did three runs each. The outcome:
stringbuilderConvenient
Took PT6.988S / Took PT6.8S / Took PT6.68S
stringbuilderWithDirectCalcs:
Took PT6.17S / Took PT6.776S / Took PT6.692S
stringbuilderHandCrafted
Took PT18.205S / Took PT16.035S / Took PT17.025S
So, scanning the String by hand and sticking the StringBuilder together step by step seems out of the question. Obviously Stephen C was right in his comment that the calculations happen anyway when converting to String. But the approach based on Stringbuilder.reverse and handcalculating each position are pretty close (and any difference might be due to minor runtime fluctuations). So, one might choose the StringBuilder.reverse method over calculating each position by hand for readability with about the same performance.

Related

How to put numbers to array in while loop in java?

I am trying to add two binary numbers and then get their sum in binary system. I got their sum in decimal and now I am trying to turn it into binary. But there is problem that when I take their sum (in decimal) and divide by 2 and find remainders(in while loop), I need to put remainders into array in order print its reverse. However, there is an error in array part. Do you have any suggestions with my code? Thanks in advance.
Here is my code:
import java.util.Scanner;
public class ex1 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int m = scan.nextInt();
int k = dec1(n)+dec2(m);
int i=0,c;
int[] arr= {};
while(k>0) {
c = k % 2;
k = k / 2;
arr[i++]=c; //The problem is here. It shows some //error
}
while (i >= 0) {
System.out.print(arr[i--]);
}
}
public static int dec1(int n) {
int a,i=0;
int dec1 = 0;
while(n>0) {
a=n%10;
n=n/10;
dec1= dec1 + (int) (a * Math.pow(2, i));
i++;
}
return dec1;
}
public static int dec2(int m) {
int b,j=0;
int dec2 = 0;
while(m>0) {
b=m%10;
m=m/10;
dec2= dec2 + (int) (b * Math.pow(2, j));
j++;
}
return dec2;
}
}
Here:
int[] arr= {};
creates an empty array. Arrays don't grow dynamically in Java. So any attempt to access any index of arr will result in an ArrayIndexOutOfBounds exception. Because empty arrays have no "index in bounds" at all.
So:
first ask the user for the count of numbers he wants to enter
then go like: int[] arr = new int[targetCountProvidedByUser];
The "more" real answer would be to use List<Integer> numbersFromUsers = new ArrayList<>(); as such Collection classes allow for dynamic adding/removing of elements. But for a Java newbie, you better learn how to deal with arrays first.
Why are you using two different methods to do the same conversion? All you need is one.
You could have done this in the main method.
int k = dec1(n)+dec1(m);
Instead of using Math.pow which returns a double and needs to be cast, another alternative is the following:
int dec = 0;
int mult = 1;
int bin = 10110110; // 128 + 48 + 6 = 182.
while (bin > 0) {
// get the right most bit
int bit = (bin % 10);
// validate
if (bit < 0 || bit > 1) {
throw new IllegalArgumentException("Not a binary number");
}
// Sum up each product, multiplied by a running power of 2.
// this is required since bits are taken from the right.
dec = dec + mult * bit;
bin /= 10;
mult *= 2; // next power of 2
}
System.out.println(dec); // prints 182
An alternative to that is to use a String to represent the binary number and take the bits from the left (high order position).
String bin1 = "10110110";
int dec1 = 0;
// Iterate over the characters, left to right (high to low)
for (char b : bin1.toCharArray()) {
// convert to a integer by subtracting off character '0'.
int bit = b - '0';
// validate
if (bit < 0 || bit > 1) {
throw new IllegalArgumentException("Not a binary number");
}
// going left to right, first multiply by 2 and then add the bit
// Each time thru, the sum will be multiplied by 2 which shifts everything left
// one bit.
dec1 = dec1 * 2 + bit;
}
System.out.println(dec1); // prints 182
One possible way to display the result in binary is to use a StringBuilder and simply insert the converted bits to characters.
public static String toBin(int dec) {
StringBuilder sb = new StringBuilder();
while (dec > 0) {
// by inserting at 0, the bits end up in
// correct order. Adding '0' to the low order
// bit of dec converts to a character.
sb.insert(0, (char) ((dec & 1) + '0'));
// shift right for next bit to convert.
dec >>= 1;
}
return sb.toString();
}

bad result of my code

I seem to have a problem, where the output I expect is:
9000 + 200 + 50 + 6
But I get:
90000 + 2000 + 500 + 60
Here is my code:
class Kata
{
public static String expandedForm(int num) {
String s = String.valueOf(num);
StringBuilder result = new StringBuilder();
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == '0') continue;
result.append(s.charAt(i) + makesZero(s.length() - i));
if(i != s.length() - 1) result.append(" + ");
}
return result.toString();
}
public static String makesZero(int num) {
StringBuilder result = new StringBuilder();
for(int i = 0; i < num; i++)
result.append("0");
return result.toString();
}
}
public class Main {
public static void main(String args[]) {
System.out.println(Kata.expandedForm(9256));
}
}
At
result.append(s.charAt(i) + makesZero(s.length() - i));
line you are appending character at position i and length - i zeroes. Lets see what happens for s="9256".
If i=0
s.charAt(i)->s.charAt(0)->'9' (that looks OK)
makesZero(s.length() - i) -> makesZero(4 - 0)) -> makesZero(4) -> "0000".
So as you see you are adding one extra zero because you didn't take into account that while 9 represents thousands, but thousands despite having 4 digits should have 3 zeroes. So you need to reduce one zero with
makesZero(s.length() - i - 1).
BTW builder.append(foo + bar) (when + represents concatenation, not addition) should be written as builder.append(foo).append(bar). Otherwise you are ending with something like
builder.append(new StringBuilder().append(foo).append(bar).toString())
which means you still need to create separate builder for each +.
We are using StringBuilder#append precisely so we could avoid + and such unnecessary object creation.
You're dealing with a classic off-by-one error. This is easily solved, but the larger problem with your approach is that you are solving the problem in an unnatural way, which makes your code more difficult to understand and debug. Determining how many zeroes to add is fundamentally a math problem but you are treating it like a string problem, which reduces the expressiveness of your code.
Here is a suggested rewrite of your expandedForm method that approaches this problem in a different way.
public static String expandedForm(int num) {
if (num == 0)
return "0";
int zeroes = (int) Math.log10(num);
StringBuilder result = new StringBuilder();
while (zeroes >= 0) {
int multiple = (int) Math.pow(10, zeroes);
int digit = num / multiple;
result.append(String.valueOf(digit * multiple));
if (zeroes > 0)
result.append(" + ");
num = num % multiple;
--zeroes;
}
return new String(result);
}
Just start your loop with i = 1 and i <= s. length()

Convert semver version string (10.2.3) to long

Here's a fun task...
Given a lot of version strings - assuming they are more or less semantic version semantic version numbers like 1.2.3 - what's a way to convert that to a long (in Java), so that it holds that "1.2.34" is less than "12.3.0"?
Here's what I have so far
public static Long toLong(String version) {
if (version == null || version.isEmpty()) {
return 0L;
}
String[] parts = version.split("[^0-9]");
long number = 0L;
long factor = 1;
for (int b = parts.length - 1; b >= 0; b--) {
try {
Long l = Long.parseLong(parts[b]);
number += l * factor;
factor = factor * 100;
} catch (NumberFormatException e){
// silently ignored
}
}
return number;
}
It assumes no position in the string has more than two digits (so 1.2.3.4567) will not work properly, but I can live with that. But I'd like to have something faster.
You can perform a similar transformation within String:
// add "." to format the major version
("." + versionString).
// replace each "." with "a00"
replaceAll("\\.", "a00").
// keep 2 digits, remove "a" and extra leading "0"
replaceAll("a0+([0-9]{2})", "$1");
This method can be easily adopted for different number of significant digits and/or different formats of the input string. Performance is ~2.4x slower than that of your toLong method (2.5 s to format 1M version strings). If performance is more important than simplicity of code, this is about 5.5x faster (0.2 s for 1M strings), than your toLong method:
public static Long toLong2(String versionString)
{
if (versionString == null || versionString.isEmpty() )
{
return 0L;
} // end if empty
char[] C = versionString.toCharArray();
int i, i1 = 0, i2 = C.length;
Long l, number = 0L, factor = 1L;
try
{
for (i = C.length - 1; i > 0; i--)
{
if (C[i] == '.')
{
i1 = i + 1;
l = Long.parseLong(versionString.substring(i1, i2) );
i2 = i;
number += l * factor;
factor = factor * 100L;
} // end if '.'
} // end for i
l = Long.parseLong(versionString.substring(0, i2) );
number += l * factor;
}
catch (NumberFormatException e)
{
// silently ignored
} // end try
return number;
} // end method toLong2

How to decompress a string such as "a3b3" to aaabbb? [duplicate]

This question already has answers here:
Run-length decompression
(6 answers)
Closed 9 years ago.
I'm trying to take user input like a3b3 and decompress it to aaabbb. This is the code I came up with, and it prints a33b.
String getDecompressedText() {
int i;
int n = 1;
String d = "";
for (i = 0; i < compressedText.length(); i++){
if (Character.isDigit(compressedText.charAt(i)) == true) {
while (n < compressedText.charAt(i)-'0') {
d += compressedText.charAt(i);
n++;
}
}
else
d += compressedText.charAt(i);
}
return d;
here's your algorithm now:
for each character:
if it's not a digit, print it
if it is a digit, print the digit itself "digit - 1" times
not ideal. A few issues:
you printing the digit, not the letter preceding it. Use charAt(i-1)
you increment n, but never reset it back to 1. You should do that in the for loop.
you should indeed print the letter n - 1 times, since it got printed out once all by itself, so that's good
use a StringBuilder
the algorithm will break for things like a14 - 2-digit counts.
public static void main(String[] args) {
String compressedText = "a3b3";
int i;
int n = 1;
String d = "";
for (i = 0; i < compressedText.length(); i++) {
if (Character.isDigit(compressedText.charAt(i))) {
while (n < compressedText.charAt(i) - '0') {
d += compressedText.charAt(i - 1);
n++;
}
n = 0;
} else {
d += compressedText.charAt(i);
}
}
System.out.println(d);
}
Output:
aaabbbb
2 issues:
d += compressedText.charAt(i - 1); // Take the previous character, no the '3'
n = 0; // Reset the counter
Some notes:
Use a StringBuilder for concatenation in a loop
This will only work for single-digit numbers (0 - 9)

how can i add values from a loop in java

I've recently been given question for uni that is in regards to a credit card statement which says i have a string of numbers, then i convert these numbers to separate integers then i increment them by the power of 10 depending on their position in the string using horners method
i then have to add the values i get from the loop to make 1 whole integer.
I Know this is an odd way to convert a string to an int but my assignment states that i have to use horners method to convert the string rather than use the inbuilt java classes/methods
My question is, How can i add the separate weighted numbers and concatenate them into one single number.
If it helps an example would be,
Given a card number 1234, the number is weighted according to its position and length so:
1 - 1000
2 - 200
3 - 30
4 - 4
Then these are added to create a whole number
1, 2, 3,4 ---> 1234
Here is my code thus far
public static long toInt(String digitString) {
long answer = 0;
long val = 0;
String s = "";
for (int j = 0; j < digitString.length(); j++) {
val = digitString.charAt(j) - '0';
val = (long) (val * Math.pow(10, (digitString.length() - 1) - j));
System.out.println(val);
}
return answer;
}
Most probably I am not following you, because this sounds too simple.
But to return a long (or integer) all you have to do is to sum these numbers:
public static long toLong(String digitString) {
long answer = 0;
long val = 0;
for (int j = 0; j < digitString.length(); j++) {
val = digitString.charAt(j) - '0';
val = (long) (val * Math.pow(10, (digitString.length() - 1) - j));
answer += val; // here! :)
//System.out.println(val);
}
return answer;
}
Please note that this is not going to work with negative numbers, so here is a more complex version:
public static long toLong(String digitString) {
long answer = 0;
long val = 0;
boolean negative = false;
int j = 0;
if (digitString.charAt(0) == '-') {
negative = true;
j = 1;
} else if (digitString.charAt(0) == '+')
j = 1;
for (; j < digitString.length(); j++) {
if (!Character.isDigit(digitString.charAt(j)))
throw new NumberFormatException(digitString);
val = digitString.charAt(j) - '0';
val = (long) (val * Math.pow(10, (digitString.length() - 1) - j));
answer += val;
}
return negative ? -answer : answer;
}
This code will work with negative numbers and with weird numbers that start with a + sign as well. If there is any other character, it will throw an exception.
I think your code is not Object-Oriented and really hard to read and understand.
Basic, the problem is a mapping and really simple.
If you are writing code in Java, better to use in OO way, though I don't like java very much.
Checkout my code
#Test
public void testCardScoreSystem() {
Map<String, String> scoreMapping = new HashMap<String, String>();
scoreMapping.put("1", "1000");
scoreMapping.put("2", "200");
scoreMapping.put("3", "30");
scoreMapping.put("4", "4");
String[] input = {"1", "2", "3", "4"};
long score = 0;
for (String str : input) {
String mappedValue = scoreMapping.get(str);
if (mappedValue == null) {
throw new RuntimeException("Hey dude, there is no such score mapping system! " + str);
}
score += Long.valueOf(mappedValue);
}
System.out.println(score);
}

Categories