1

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);
iknow
  • 8,358
  • 12
  • 41
  • 68
  • 5
    "**10 is to get 9876543210 as long value;*" - you can just do `9876543210L`. – Fureeish Aug 03 '20 at 22:56
  • 3
    Convert the long value to a string, then reverse the string. See [Reverse a string in Java](https://stackoverflow.com/questions/7569335/reverse-a-string-in-java) – kaya3 Aug 03 '20 at 22:59
  • 2
    That leading zero will get stripped every time if you keep it as a long. – Liftoff Aug 03 '20 at 22:59

3 Answers3

3

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());
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
2

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());
iknow
  • 8,358
  • 12
  • 41
  • 68
  • @georgezhang006 Note that going back to `long` from the `String`, e.g. by `Long.parseLong(reversed)` might drop leading zeroes, resulting in `987654321`. – Zabuzard Aug 03 '20 at 23:15
  • 1
    Yeah, of course. I don't know how questioner wants to use this reversed value but if as a number It is important to trim `0` at the beginning and `-` at the end – iknow Aug 03 '20 at 23:16
1

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.

Frank Hopkins
  • 639
  • 4
  • 12
  • Except that it doesn't avoid calculations for each position. They happen inside `valueOf`. Look at the source code ... – Stephen C Aug 03 '20 at 23:30