在 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
Quickest Method to Reverse in String in C#.net
提问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:
我认为就地进行比较可能会更快。如果你反转字符串,你必须:
- Instantiate a new string object (or StringBuffer object)
- Copy the data (in reverse) from the first string to the new string
- Do your comparison.
- 实例化一个新的字符串对象(或 StringBuffer 对象)
- 将数据(反向)从第一个字符串复制到新字符串
- 做你的比较。
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 int
s instead of ulong
s (but much slower, otherwise).
尽管这回答了 OP 的问题,但根据我的测试,ggf31416和配置器提供的解决方案解决了 OP 的实际需求,速度提高了约 30%。配置器的解决方案比 ggf31416 的解决方案快一点,如果你将它转换为静态方法并使用int
s 而不是ulong
s (但要慢得多,否则)。
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 Ed Guiness
回答by Mladen Prajdic
回答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;
}
}
}