Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quickest Method to Reverse in String in C#.net

Tags:

c#

I'm currently writing a quick solution for Euler Problem #4 where one must find the largest palindromic number from the product of two 3-digit numbers.

To identify if a number is palindromic, you would obviously compare a reverse of the number with the original.

Since C# doesn't have a built in String.Reverse() method, what is the quickest way to reverse a string?

I will be testing all the suggested solution in a loop with 100,000,000 iterations. The correct answer will be given to the person who submitted the fastest solution.

I will be testing the solution in a C#.Net 3.5 console application

like image 504
GateKiller Avatar asked Jan 11 '09 17:01

GateKiller


4 Answers

Wouldn't reversing the number be faster?

// unchecked code, don't kill me if it doesn't even compile.
ulong Reverse(ulong number) {
    ulong result = 0;

    while (number > 0) {
        ulong digit = number % 10;
        result = result * 10 + digit;
        number /= 10;
    }

    return result;
}
like image 188
configurator Avatar answered Nov 02 '22 02:11

configurator


A you want to compare a number with its reverse it may be faster to reverse the number using division rather than converting it to a string. I still need to test the speed of it.

 private static int Reverse(int num) {
     int res = 0;
     while (num > 0) {
        int rm ;
        num = Math.DivRem(num, 10, out rm);
        res = res * 10 + rm;
     }
     return res;
  }

EDIT: DivRem was about 1% faster than division and module in my computer. A speed optimization is exit if the last digit is 0:

  private static int Reverse(int num) {
     int res = 0;
     int rm;
     num = Math.DivRem(num, 10, out rm);
     //Some magic value or return false, see below.
     if (rm == 0) return -1 ; 
     res = res * 10 + rm;
     while (num > 0) {
        num = Math.DivRem(num, 10, out rm);
        res = res * 10 + rm;
     }
     return res ;
  }

Making the method return a bool was slightly slower than comparing to a bool in a loop in my computer, but I don't understand why. Please test in your computer.

Multiplication and bit-shifing should be faster than division but probably are not precise enough. EDIT: using long seems be precise enough.

  private static int FastReverse(int num) {
     int res = 0;
     int q = (int)((214748365L * num) >> 31);
     int rm = num - 10 * q;
     num = q;
     if (rm == 0) return -1;
     res = res * 10 + rm;
     while (num > 0) {
        q = (int)((214748365L * num) >> 31);
        rm = num - 10 * q;
        num = q;
        res = res * 10 + rm;
     }
     return res;
  }

(214748365L * num) >> 31 is equal to i / 10 until 1,073,741,829 where 1 / 10 gives 107374182 and the multiplication + binary shifting gives 107374183.

like image 33
ggf31416 Avatar answered Nov 02 '22 02:11

ggf31416


I think it might be faster to do the comparison in-place. If you reverse the string, you've got to:

  1. Instantiate a new string object (or StringBuffer object)
  2. Copy the data (in reverse) from the first string to the new string
  3. Do your comparison.

If you perform the comparison in place, you do only the last step. An even then, your comparison is only half the string (or half - 0.5, in the event of an odd number of characters). Something like the following should work:

static bool IsPalindromic(string s){
    int len = s.Length;
    int half = len-- >> 1;
    for(int i = 0; i < half; i++)
        if(s[i] != s[len - i])
            return false;
    return true;
}

EDIT:

Although this answers the OP's question, the solutions offered by ggf31416 and configurator solve the OP's real need about 30% faster, by my tests. configurator's solution is a tiny bit faster than ggf31416's, if you convert it to a static method and use ints instead of ulongs (but much slower, otherwise).


Incidentally, running through these examples to solve the problem the OP mentions (finding the largest palindromic product of any two three-digit numbers) with the simple (perhaps naïve) loop below:

for(int i = 100; i < 1000; i++)
    for(int j = i; j < 1000; j++) // calculations where j < i would be redundant
        ...

yields the following results on my machine:

IsPalindromic(product.ToString()) took 0.3064174 seconds.
ggf31416Reverse(product) == product took 0.1933994 seconds.
configuratorReverse(product) == product took 0.1872061 seconds.

Each produces the correct result of 913 * 993 = 906609.

like image 39
P Daddy Avatar answered Nov 02 '22 04:11

P Daddy


Performance: Fastest string reversing algorithms... (final results)

like image 36
Ed Guiness Avatar answered Nov 02 '22 03:11

Ed Guiness