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

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

要确定一个数字是否是回文,您显然会将数字的反转与原始数字进行比较。

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

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

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

我认为在原地进行比较可能会更快。 如果你反转字符串,你必须:

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

如果您执行比较,则只执行最后一步。 即便如此,你的比较只是字符串的一半(或半数 – 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; } 

编辑:

虽然这回答了OP的问题,但是ggf31416和配置器提供的解决方案通过我的测试解决了OP的实际需求快了约30%。 configurator的解决方案比ggf31416快一点,如果你将它转换为静态方法并使用int而不是ulong (否则慢得多)。


顺便提一下,通过这些例子解决问题,OP提到(找到任意两个三位数的最大回文产品),下面简单(可能是天真的)循环:

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

在我的机器上产生以下结果:

 IsPalindromic(product.ToString())耗时0.3064174秒。
 ggf31416Reverse(产品)==产品耗时0.1933994秒。
 configuratorReverse(产品)==产品耗时0.1872061秒。

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

不会逆转数字更快?

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

如果您想要将数字与其反向进行比较,则使用除法将数字反转而不是将其转换为字符串可能会更快。 我仍然需要测试它的速度。

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

编辑: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 ; } 

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

乘法和位移应该比除法快,但可能不够精确。 编辑:使用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等于i / 10,直到1,073,741,829,其中1/10给出107374182,乘法+二进制移位给出107374183。

性能:最快的字符串反转算法……(最终结果)

 string test = "ABC"; string reversed = new String(test.ToCharArray().Reverse().ToArray()); 
 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); } 

编辑:Doh! 忘了把perf的长度减半:)

我发现在C#中反转字符串的最快方法是使用以下代码。 它一次读取的速度更快,而不是char的长度为16位。 在调试模式下,它会更快,直到你达到约93个字符。 任何比Array.Reverse()更长的东西。 使用发布版本并在IDE外部运行,此方法将以任何字符串长度将Array.Reverse()从水中吹出。

 char[] MyCharArray = MyString.ToCharArray(); UIntStringReverse(ref MyCharArray); //Code to reverse is below. string ReversedString = new string(MyCharArray); private static unsafe void UIntStringReverse(ref char[] arr) { uint Temp; uint Temp2; fixed (char* arrPtr = &arr[0]) { uint* p, q; p = (uint*)(arrPtr); q = (uint*)(arrPtr + arr.LongLength - 2); if (arr.LongLength == 2) { Temp = *p; *p = ((Temp & 0xFFFF0000) >> 16) | ((Temp & 0x0000FFFF) << 16); return; } while (p < q) { Temp = *p; Temp2 = *q; *p = ((Temp2 & 0xFFFF0000) >> 16) | ((Temp2 & 0x0000FFFF) << 16); *q = ((Temp & 0xFFFF0000) >> 16) | ((Temp & 0x0000FFFF) << 16); p++; q--; } } } 

试试这个: http : //weblogs.sqlteam.com/mladenp/archive/2006/03/19/9350.aspx

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

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

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

每次运行后,Stopwatch类都需要重置。 以下代码已得到纠正

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