更有效的打印回文数字的算法和2的权力也是回文

时间:2018-06-03 08:03:26

标签: c# algorithm

我正在寻找更有效的算法来打印回文数字(例如1001),他们的权力为2(1001 * 1001 = 1002001)也是回文。在我的算法中,我认为我做了不必要的检查,以确定数字是否是回文。我该如何改进呢?

在[1000,9999]范围内,我发现了这种3个数字:1001,1111和2002。

这是我的算法:

for (int i = n; i <= m; i++)
{
    if (checkIfPalindromic(i.ToString()))
    {
        if (checkIfPalindromic((i * i).ToString()))
             Console.WriteLine(i);
    }
}

这是我确定数字是否是回文的方法:

static bool checkIfPalindromic(string A)
{
    int n = A.Length - 1;
    int i = 0;
    bool IsPalindromic = true;

    while (i < (n - i))
    {
        if (A[i] != A[n - i])
        {
            IsPalindromic = false;
            break;
        }

        i++;
    }

    return IsPalindromic;
}

6 个答案:

答案 0 :(得分:1)

你已经看起来效率很高

比例正在检查1,000,000个整数

注意:我使用longs

免责声明:我必须承认这些结果有点粗略,我添加了更多缩放,以便您可以看到

<强>结果

Mode            : Release
Test Framework  : .Net 4.7.1
Benchmarks runs : 10 times (averaged)

Scale : 1,000
Name     |  Average |  Fastest | StDv |  Cycles | Pass |    Gain
-----------------------------------------------------------------
Mine2    | 0.107 ms | 0.102 ms | 0.01 | 358,770 | Yes  |  5.83 %
Original | 0.114 ms | 0.098 ms | 0.05 | 361,810 | Base |  0.00 %
Mine     | 0.120 ms | 0.100 ms | 0.03 | 399,935 | Yes  | -5.36 %


Scale : 10,000
Name     |  Average |  Fastest | StDv |    Cycles | Pass |    Gain
-------------------------------------------------------------------
Mine2    | 1.042 ms | 0.944 ms | 0.17 | 3,526,050 | Yes  | 11.69 %
Mine     | 1.073 ms | 0.936 ms | 0.19 | 3,633,369 | Yes  |  9.06 %
Original | 1.180 ms | 0.920 ms | 0.29 | 3,964,418 | Base |  0.00 %


Scale : 100,000
Name     |   Average |  Fastest | StDv |     Cycles | Pass |   Gain
--------------------------------------------------------------------
Mine2    | 10.406 ms | 9.502 ms | 0.91 | 35,341,208 | Yes  | 6.59 %
Mine     | 10.479 ms | 9.332 ms | 1.09 | 35,592,718 | Yes  | 5.93 %
Original | 11.140 ms | 9.272 ms | 1.72 | 37,624,494 | Base | 0.00 %


Scale : 1,000,000
Name     |    Average |    Fastest | StDv |      Cycles | Pass |    Gain
-------------------------------------------------------------------------
Original | 106.271 ms | 101.662 ms | 3.61 | 360,996,200 | Base |  0.00 %
Mine     | 107.559 ms | 102.695 ms | 5.35 | 365,525,239 | Yes  | -1.21 %
Mine2    | 108.757 ms | 104.530 ms | 4.81 | 368,939,992 | Yes  | -2.34 %

Mode            : Release
Test Framework  : .Net Core 2.0
Benchmarks runs : 10 times (averaged)

Scale : 1,000,000
Name     |    Average |   Fastest |  StDv |      Cycles | Pass |    Gain
-------------------------------------------------------------------------
Mine2    |  95.054 ms | 87.144 ms |  8.45 | 322,650,489 | Yes  | 10.54 %
Mine     |  95.849 ms | 89.971 ms |  5.38 | 325,315,589 | Yes  |  9.79 %
Original | 106.251 ms | 84.833 ms | 17.97 | 350,106,144 | Base |  0.00 %

<强>鉴于

protected override List<int> InternalRun()
{
   var results = new List<int>();
   for (var i = 0; i <= Input; i++)
      if (checkIfPalindromic(i) && checkIfPalindromic(i * (long)i))
            results.Add(i);             

   return results;
}

<强> Mine1

private static unsafe bool checkIfPalindromic(long value)
{
   var str = value.ToString();
   fixed (char* pStr = str)
   {
      for (char* p = pStr, p2 = pStr + str.Length - 1; p < p2;)
         if (*p++ != *p2--)
            return false;
   }

   return true;
}

<强> Mine2

private static bool checkIfPalindromic(long value)
{
   var str = value.ToString();
   var n = str.Length - 1;

   for (var i = 0; i < n - i; i++)
      if (str[i] != str[n - i])
         return false;

   return true;
}

答案 1 :(得分:1)

更乐观的方法是使用int代替string。这个算法快了两倍:

static int[] pow10 = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };

static bool checkIfPalindromic(int A)
{
    int n = 1;
    int i = A;
    if (i >= 100000000) { n += 8; i /= 100000000; }
    if (i >= 10000) { n += 4; i /= 10000; }
    if (i >= 100) { n += 2; i /= 100; }
    if (i >= 10) { n++; }


    int num = A / pow10[(n+1) / 2];
    for (; num % 10 == 0;)
        num /= 10;

    int reversedNum = 0;
    for (int input = A % pow10[ n / 2]; input != 0; input /= 10)
        reversedNum = reversedNum * 10 + input % 10;

    return num == reversedNum;
}

用法:

for (int i = n; i <= m; i++)
    if (checkIfPalindromic(i) && checkIfPalindromic(i * i))
             Console.WriteLine(i);

基准:

Bemchmark in range of [1000, 99999999]  on Core2Duo CPU:

This algorithm: 12261ms
Your algorithm: 24181ms

Palindromic Numbers:
1001
1111
2002
10001
10101
10201
11011
11111
11211
20002
20102

答案 2 :(得分:1)

而不是检查&#34; palindromness&#34;的数字,最好只迭代回文。为此,只需迭代数字的前半部分,然后从中组成回文。

for(int half=10;half<=99;++half)
{
    const int candidate=half*100+Reverse(half);//may need modification for odd number of digits
    if(IsPalindrome(candidate*candidate))
        Output(candidate);
}

这将使您的计划O(sqrt(m))而不是O(m),这可能会超过常数因素的所有改进。

答案 3 :(得分:0)

  

您可以使用Linq来简化代码

样品: -

str ='<t abc>1.3</t><t efg>32.3</t>';
[tokens] = regexpi(str,  '<t.*>(\d*\.\d*)</t>', 'tokens');
celldisp(tokens)

答案 4 :(得分:0)

循环到len / 2,如下所示:

C:\Python36-32\Lib\site-packages\upwork>python myAuth.py
Traceback (most recent call last):
  File "myAuth.py", line 4, in <module>
    import upwork
  File "C:\Python36-32\lib\site-packages\upwork\__init__.py", line 23, in <module>
    from upwork.client import Client
  File "C:\Python36-32\lib\site-packages\upwork\client.py", line 8, in <module>
    import urllib3
  File "C:\Python36-32\lib\site-packages\urllib3\__init__.py", line 8, in <module>
    from .connectionpool import (
  File "C:\Python36-32\lib\site-packages\urllib3\connectionpool.py", line 11, in <module>
    from .exceptions import (
  File "C:\Python36-32\lib\site-packages\urllib3\exceptions.py", line 2, in <module>
    from .packages.six.moves.http_client import (
  File "C:\Python36-32\lib\site-packages\urllib3\packages\six.py", line 203, in
load_module
    mod = mod._resolve()
  File "C:\Python36-32\lib\site-packages\urllib3\packages\six.py", line 115, in
_resolve
    return _import_module(self.mod)
  File "C:\Python36-32\lib\site-packages\urllib3\packages\six.py", line 82, in _
import_module
    __import__(name)
  File "C:\Python36-32\Lib\site-packages\upwork\http.py", line 6, in <module>
    from compatibility import HTTPError, httplib
  File "C:\Python36-32\Lib\site-packages\upwork\compatibility.py", line 8, in <module>
    from http import client as httplib
ImportError: cannot import name 'client'

答案 5 :(得分:0)

我们可以通过改变回文检查方法并使用直接整数反转方法而不是首先转换为字符串然后在字符串中循环来获得有趣的优化。

我在this question接受的答案中使用了该方法:

static int reverse(int n)
{
   int left = n;
   int rev = 0;
   int r = 0;
   while (left > 0)
   {
      r = left % 10;
      rev = rev * 10 + r;
      left = left / 10; 
   }
   return rev;
}

我还使用System.Diagnostics中的StopWatch来衡量经过的时间。

我检查数字是否为回文数字的功能是:

static bool IsPalindromicNumber(int number)
{
   return reverse(number) == number;
}

对于 n值1000 ,对于不同的m值,我得到以下经过时间的结果(以毫秒为单位):

---------------------------------------------------------
| m        | original        | mine       | optimisation|
---------------------------------------------------------
|9999      |6.3855           |4.2171      | -33.95%     |
---------------------------------------------------------
|99999     |71.3961          |42.3399     | -40.69%     |
--------------------------------------------------------- 
|999999    |524.4921         |342.8899    | -34.62%     |
---------------------------------------------------------
|9999999   |7016.4050        |4565.4563   | -34.93%     |   
---------------------------------------------------------
|99999999  |71319.658        |49837.5632  | -30.12%     |   
---------------------------------------------------------

测量值是指示性而非绝对值,因为从程序的一次运行到另一次运行它们是不同的但模式保持不变,第二种方法似乎总是更快。

使用秒表进行测量:

使用您的方法:

Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = n; i <= m; i++)
{
   if (checkIfPalindromic(i.ToString()))
   {
      if (checkIfPalindromic((i * i).ToString()))
         Console.WriteLine(i);
   }
}
stopWatch.Stop();
Console.WriteLine("First approach: Elapsed time..." + stopWatch.Elapsed + " which is " + stopWatch.Elapsed.TotalMilliseconds + " miliseconds");

我当然使用了与我的更改完全相同的方法:

使用我的方法:

Stopwatch stopWatch2 = new Stopwatch();
stopWatch2.Start();
for (int i = n; i <= m; i++)
{
   if (IsPalindromicNumber(i) && IsPalindromicNumber(i*i))
   {
      Console.WriteLine(i);
   }
}

stopWatch2.Stop();
Console.WriteLine("Second approach: Elapsed time..." + stopWatch2.Elapsed + " which is " + stopWatch2.Elapsed.TotalMilliseconds + " miliseconds");