在 C#.net 中反转字符串的最快方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/433211/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 03:12:01  来源:igfitidea点击:

Quickest Method to Reverse in String in C#.net

c#

提问by GateKiller

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.

我目前正在为欧拉问题 #4 编写一个快速解决方案,其中必须从两个 3 位数的乘积中找到最大的回文数。

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?

由于 C# 没有内置的 String.Reverse() 方法,反转字符串的最快方法是什么?

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.

我将在 100,000,000 次迭代的循环中测试所有建议的解决方案。正确答案将给予提交最快解决方案的人。

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

我将在 C#.Net 3.5 控制台应用程序中测试解决方案

采纳答案by P Daddy

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.
  1. 实例化一个新的字符串对象(或 StringBuffer 对象)
  2. 将数据(反向)从第一个字符串复制到新字符串
  3. 做你的比较。

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:

如果就地执行比较,则只需执行最后一步。即使这样,您的比较也只是字符串的一半(或一半 - 0.5,如果是奇数个字符)。像下面这样的东西应该工作:

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 ggf31416and configuratorsolve 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).

尽管这回答了 OP 的问题,但根据我的测试,ggf31416配置器提供的解决方案解决了 OP 的实际需求,速度提高了约 30%。配置器的解决方案比 ggf31416 的解决方案快一点,如果你将它转换为静态方法并使用ints 而不是ulongs (但要慢得多,否则)。



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:

顺便说一句,通过下面的简单(也许是天真的)循环,运行这些示例来解决 OP 提到的问题(找到任何两个三位数的最大回文乘积):

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.

每个都会产生 的正确结果913 * 993 = 906609

回答by JaredPar

public static String Reverse(string input) {
  var length = input.Length;
  var buffer = new char[length];
  for ( var i= 0; i < input.Length; i++ ) {
    buffer[i] = input[(length-i)-1];
  }
  return new String(buffer);
}

EDIT: Doh! Forgot to halve the length for perf :)

编辑:哦!忘记将 perf 的长度减半 :)

回答by Mladen Prajdic

string test = "ABC";
string reversed = new String(test.ToCharArray().Reverse().ToArray());

回答by Jesper Palm

string Reverse(string s)
{
  return new string(s.ToCharArray().Reverse().ToArray());
}

回答by ggf31416

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:

编辑:DivRem 比我的计算机中的除法和模块快约 1%。如果最后一位为 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.

使该方法返回 bool 比在我的计算机中与循环中的 bool 相比稍慢,但我不明白为什么。请在您的计算机上进行测试。

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

乘法和位移位应该比除法快,但可能不够精确。编辑:使用 long 似乎足够精确。

  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.

(214748365L * num) >> 31 等于 i / 10 直到 1,073,741,829,其中 1 / 10 给出 107374182,乘法 + 二进制移位给出 107374183。

回答by configurator

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;
}

回答by GateKiller

Using ggf31416's FastReverse function, here is the solution to Project Euler's Problem #4 which completes on my computer in 47ms.

使用 ggf31416 的 FastReverse 函数,这里是 Project Euler 问题 #4 的解决方案,它在 47 毫秒内在我的计算机上完成。

using System;
using System.Diagnostics;

namespace Euler_Problem_4
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch s = new Stopwatch();
            s.Start();

            int t = 0;

            for (int i = 999; i > 99; i--)
            {
                for (int j = i; j > 99; j--)
                {
                    if (i*j == FastReverse(i*j))
                    {
                        if (i * j > t)
                        {
                            t = i * j;
                        }
                    }
                }
            }

            Console.WriteLine(t);

            s.Stop();
            Console.WriteLine("{0}mins {1}secs {2}ms", s.Elapsed.Minutes, s.Elapsed.Seconds, s.Elapsed.Milliseconds);
            Console.ReadKey(true);

        }

        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;
        }
    }
}

回答by Matthew Whited

The Stopwatch class needs reset after each run. the code below has been corrected

每次运行后,秒表类都需要重置。下面的代码已更正

var d = s.ToCharArray();
Array.Reverse(d);
return s == new string(d);


using System;
using System.Diagnostics;

namespace longeststring_codegolf
{
    class Program
    {
        static void Main(string[] args)
        {
            int t = 0, v = 0;
            var sw = new Stopwatch();

            sw.Start();
            for (int i = 999; i > 99; i--)
                for (int j = 999; j > 99; j--)
                    if ((v = i * j) > t && IsPalindromicMine(v.ToString()))
                        t = v;
            sw.Stop();

            var elapsed = sw.Elapsed;
            var elapsedMilliseconds = sw.ElapsedMilliseconds;
            var elapsedTicks = sw.ElapsedTicks; 
            Console.WriteLine("Ticks: " + elapsedTicks.ToString());//~189000
            Console.WriteLine("Milliseconds: " + elapsedMilliseconds.ToString()); //~9

            sw = Stopwatch.StartNew();
            for (int i = 999; i > 99; i--)
                for (int j = 999; j > 99; j--)
                    if ((v = i * j) > t && IsPalindromic(v.ToString()))
                        t = v;
            sw.Stop();
            var elapsed2 = sw.Elapsed;
            var elapsedMilliseconds2 = sw.ElapsedMilliseconds;
            var elapsedTicks2 = sw.ElapsedTicks; 
            Console.WriteLine("Ticks: " + elapsedTicks2.ToString());//~388000
            Console.WriteLine("Milliseconds: " + elapsedMilliseconds2.ToString());//~20

        }

        static bool IsPalindromicMine(string s)
        {
            var d = s.ToCharArray();
            Array.Reverse(d);
            return s == new string(d);
        }

        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;
        }

    }
}