有效计算数字中数字出现次数的方法

时间:2016-06-09 07:30:41

标签: c# performance

我需要计算单个数字(不是0)出现在不同长度的数字(正整数)中的次数。 显而易见的解决方案是将数字转换为字符串,将数字转换为字符并迭代字符串以计算字符在字符串中出现的次数。

static int CountDigitInString(string searchString, char digit)
{
    int sum = 0;

    for (int i = 0; i < searchString.Length; i++)
    {
        if (searchString[i] == digit)
            sum++;
    }

    return sum;
}

然而,这种方法的问题在于它对我的目的来说太慢了,因为我多次运行它。

public static void Run()
{
    for (int i = 0; i < 1000000; i++)
    {
        CountDigitInString(i.ToString(), (char)j);
    }
}

在我注意到这个过程耗费了太多时间之后,CPU采样分析器向我展示了问题是转换为字符串。

那么,我如何有效地计算一个数字(单个数字,而不是数字)出现在一个数字(任何长度)中的次数?

4 个答案:

答案 0 :(得分:2)

我找到了一种平均速度约为3倍的方法(使用秒表检查):

static int CountDigitsInString(int number, int digit)
{
    int sum = 0;

    while (number != 0)
    {
        if (number % 10 == digit)
            sum++;
        number /= 10;
    }

    return sum;
}

编辑: 我找到了一种比上面那么快4倍的方法。在开始之前,请注意,对于连续数字中数字外观的情况,此解决方案仅对 有效。

我突然意识到,如果你计算了数字&#34; d&#34;出现在一个数字&#34; A&#34;,然后你不必重新计算次数&#34; d&#34;出现在&#34; A + 1&#34;知道它是什么。 例如,如果我知道数字3在数字35312336中出现4次,我可以知道它在下一个连续数字35312337中仍然会出现4次,没有实际计数。 我能做到这一点的原因是计数只会在三种情况中的一种情况下发生变化:
1)当&#34; A - 1&#34;的最后一位数字时是一个9岁,#34; A&#34;因数字被遗留而可能完全改变。 这是我们实际需要计算的唯一情况(尽管理论上可以通过检查结转的数字来进一步优化它,看看它们是否会影响总数,但这让我觉得过于复杂) 。
2)当&#34; A - 1&#34;的最后一位数字时是&#34; d - 1&#34;,我们知道次数&#34; d&#34;出现在&#34; A&#34;增加了一个。
3)当&#34; A - 1&#34;的最后一位数字时是的,我们知道次数&#34; d&#34;出现在&#34; A&#34;减少了一个。

这意味着你只需计算&#34; d&#34;的外观。在&#34; A&#34;在十分之一的案例中使用算术运算!

public static void Run()
{
    int digit = 1;
    int count = 0;
    for (int i = 0; i < 100000; i++)
    {
        int previousLastDigit = (i - 1) % 10;

        if (previousLastDigit == (digit - 1))
            count++;
        else if (previousLastDigit == 9)
            count = CountDigitsInString(i, digit);
        else if (previousLastDigit == digit)
            count--;
        Console.WriteLine(digit + " appears " + count + " times in the number " + i);
    }
}

CountDigitsInString函数是上面的函数。

答案 1 :(得分:2)

这是@shaitibber解决方案的更优化版本。它用乘法替换一个除法,并为0,0返回1。它快了大约20%。

static int CountDigitsInString2(int number, int digit)
{
    int sum = 0;

    do
    {
        int n2 = number / 10;
        if (number - n2 * 10 == digit)
            sum++;
        number = n2;
    } while (number != 0);

    return sum;
}

这里的解决方案比这快三倍(但不适用于0位数,这不是必需的)。它预先计算数字0..9999的结果。

private static int[][] cache = new int[10][];
private const int cacheSize = 10000;//or 100000

private static int[] initCache(int digit)
{
    var ca = cache[digit] = new int[cacheSize];
    for (int i = 0; i < ca.Length; ++i)
    {
        ca[i] = CountDigitsInString2(i, digit);
    }
    return ca;
}

static int CountDigitsInString3(int number, int digit)
{
    var ca = cache[digit] ?? initCache(digit);
    int sum = 0;

    while (number != 0)
    {
        int n2 = number / cacheSize;
        sum += ca[number - n2 * cacheSize];
        number = n2;
    };

    return sum;
}

答案 2 :(得分:0)

这是一个LINQ的小片段给你另一种方法(没有跑秒表)

var number = 11334511;
var digit = 1;
var digitAsChar = Convert.ToChar(digit.ToString().ToLower());

// Occurence will be 4
var occurence = number.ToString().ToLower().Count(s => s == digitAsChar);

答案 3 :(得分:0)

我建议你在字符串上使用LINQ。

来源:https://msdn.microsoft.com/en-us/library/mt693025.aspx

static int CountDigitInString(string number, char digit)
{
   int count = number.Count(ns => ns == digit);
   return count;
}
相关问题