c#优化循环使用大数字

时间:2013-11-19 22:35:49

标签: c#

我有这个代码,它找到给定范围内仅包含​​3和5的数字,并且是多项式(对称,例如3553)。问题是数字在1到10 ^ 18之间,所以在某些情况下我必须使用大数字,并且使用BigInteger会使程序太慢,所以有没有办法解决这个问题?这是我的代码:

namespace Lucky_numbers
{
    class Program
    {
        static void Main(string[] args)
        {

            string startString = Console.ReadLine();
            string finishString = Console.ReadLine();
            BigInteger start = BigInteger.Parse(startString);
            BigInteger finish = BigInteger.Parse(finishString);

            int numbersFound = 0;

            for (BigInteger i = start; i <= finish; i++)
            {
                if (Lucky(i.ToString()))
                {
                    if (Polyndrome(i.ToString()))
                    {
                        numbersFound++;
                    }
                }

            }
        }

        static bool Lucky(string number)
        {
            if (number.Contains("1") || number.Contains("2") || number.Contains("4") || number.Contains("6") || number.Contains("7") || number.Contains("8") || number.Contains("9") || number.Contains("0"))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        static bool Polyndrome(string number)
        {
            bool symetrical = true;

            int middle = number.Length / 2;
            int rightIndex = number.Length - 1;

            for (int leftIndex = 0; leftIndex <= middle; leftIndex++)
            {
                if (number[leftIndex] != number[rightIndex])
                {
                    symetrical = false;
                    break;
                }
                rightIndex--;
            }
            return symetrical;
        }
    }
}

编辑:原来它不是BigInteger,这是我糟糕的实现。

7 个答案:

答案 0 :(得分:2)

您可以使用ulong

  

大小:无符号64位整数

     

范围: 018,446,744,073,709,551,615

但我猜这里BigInteger不是问题。我认为你应该为回文创建算法而不是强力增量+检查解决方案。

加成

这是我在5分钟内写的一个palyndrome发生器。我认为它会比你的方法快得多。你能测试一下并告诉它有多快吗?我很好奇。

public class PalyndromeGenerator
{
    private List<string> _results;
    private bool _isGenerated;
    private int _length;
    private char[] _characters;

    private int _middle;
    private char[] _currentItem;

    public PalyndromeGenerator(int length, params char[] characters)
    {
        if (length <= 0)
            throw new ArgumentException("length");
        if (characters == null)
            throw new ArgumentNullException("characters");
        if (characters.Length == 0)
            throw new ArgumentException("characters");

        _length = length;
        _characters = characters;
    }

    public List<string> Results
    {
        get
        {
            if (!_isGenerated)
                throw new InvalidOperationException();

            return _results.ToList();
        }
    }

    public void Generate()
    {
        _middle = (int)Math.Ceiling(_length / 2.0) - 1;
        _results = new List<string>((int)Math.Pow(_characters.Length, _middle + 1));
        _currentItem = new char[_length];

        GeneratePosition(0);

        _isGenerated = true;
    }

    private void GeneratePosition(int position)
    {
        if(position == _middle)
        {
            for (int i = 0; i < _characters.Length; i++)
            {
                _currentItem[position] = _characters[i];
                _currentItem[_length - position - 1] = _characters[i];
                _results.Add(new string(_currentItem));
            }
        }
        else
        {
            for(int i = 0; i < _characters.Length; i++)
            {
                _currentItem[position] = _characters[i];
                _currentItem[_length - position - 1] = _characters[i];
                GeneratePosition(position + 1);
            }
        }
    }
}

用法:

var generator = new PalyndromeGenerator(6, '3', '5');
generator.Generate();
var items = generator.Results.Select(x => ulong.Parse(x)).ToList();

答案 1 :(得分:2)

奇怪的谜语,但如果我理解了这个要求,可以简化。 我首先将这些数字映射到二进制,因为只有两个可能 “幸运”数字,然后通过二进制计数生成数字,直到 我已经完成了9位。然后反映它的全部数字 将0转换为3和1至5。

示例1101  反映它= 10111101 - &gt; 53555535

从0到111111111

执行此操作

答案 2 :(得分:2)

声明开始和结束在课堂内是静态的。

将方法Lucky更改为:

static bool Lucky(string number)
{
    return !(number.Contains("1") || number.Contains("2") || number.Contains("4") || number.Contains("6") || number.Contains("7") || number.Contains("8") || number.Contains("9") || number.Contains("0"));
}

此外,您可以使用并行库来并行化计算。 您可以使用Parallel.For

,而不是使用常规for循环

答案 3 :(得分:1)

以不同的方式查看问题 - 最多9个字符的字符串 (仅使用'3''5')你可以使?对于每个字符串,您可以制作2个回文(一个重复最后一个字符,一个不重复)。

e.g。

3 -> 33
5 ->, 55
33 -> 333, 3333
35 -> 353, 3553
53 -> 535, 5335
...

答案 4 :(得分:0)

我唯一的建议是使用第三方库,如intx或一些非托管代码。 intx作者报告说它在某些情况下比BigInteger工作得更快:“.NET 4.0中引入了System.Numerics.BigInteger类,所以我对这个解决方案的性能感兴趣。我做了一些测试(从GitHub获取测试代码)和似乎BigInteger在标准操作上的性能与IntX相当,但在FHT发挥作用时开始失败(例如,当乘以非常大的整数时)。“

答案 5 :(得分:0)

由于数字必须是对称的,您只需要检查数字的前半部分。您不需要检查18位数字,您只需要检查9位数字然后交换字符的顺序并将它们作为字符串添加到后面。

答案 6 :(得分:0)

我能想到的一件事是,如果你计算包含3或5的整数,你就不需要遍历整个数字列表在你的开始和之间结束范围。

相反,请将您的字符集视为“3”或“5”。然后你可以简单地完成数字本身 half 的允许排列,让另一半完成以成功创建一个综合症。

这种方法有一些规则可以提供帮助,例如:

  • 如果起始编号的最左边数字大于5,则无需尝试该特定数字的数字。
  • 如果两个数字都落在相同的数字位上,但最左边的数字不会遍历/包含5或3,则无需处理。

制定一些这样的规则可能有助于检查每个可能的排列。

因此,例如,您的 Lucky 功能将变得更加符合以下方面:

    static bool Lucky(string number)
    {
        if((number[0] != '3') && (number[0] != '5'))
        {
            return false;
        }                  //and you could continue this for the entire string
        ...
    }