最近我在接受采访时被问到如何编写算法来计算给定数字中的位数。因此,例如,如果给我一个数字500,结果将是3.如果给我一个数字15345,结果将是5.
我想出了两个可能的解决方案:
递归地将数字除以10,直到结果小于1,然后返回我所做的递归计数。
将数字转换为字符串,然后计算此字符串中元素的数量。
然后我被问到在处理非常大的数字时哪个操作更有效,我无法给出一个好的答案。所以我的问题是这里的正确答案是什么 - 哪种算法更快,为什么?
答案 0 :(得分:1)
好吧,要将整数转换为字符串,基本itoa
(整数到字符串)函数的工作方式如下:
result = ""
while (number > 0)
{
digit = number % 10
append digit to result
number = number / 10
}
因此,您的第一个和第二个解决方案之间没有太大区别。第一个解决方案将采用 O(n)迭代,其中 n 是整数中的位数。第二种解决方案具有相同的复杂性,另外计算 O(n)时间内字符串中的 n 位数,总计 O(2n) = O(n)复杂性。
其他算法也是可能的。例如,您可以查看设置的最高位,并将其与值表进行匹配。
答案 1 :(得分:1)
我计时了三个变种:
长度为10的倍数。我每次运行10000次。
以微秒为单位的结果:
length division logarithm string length
---------------------------------------------------
10 7 10 16
20 14 14 26
30 28 14 41
40 46 14 59
50 73 14 80
60 91 14 80
70 113 14 98
80 136 14 106
90 170 14 116
100 197 14 129
这些数据中有各种来源的文物,但我认为你明白这一点。
答案 2 :(得分:0)
这在很大程度上取决于数字的给定方式。我会解释你给了一个存储为机器整数的数字。在那种情况下,我认为最重要的是采用数字的对数,这应该在不变的时间给出答案。
你的答案都是以线性时间运行的,所以应该考虑它们 等效。
答案 3 :(得分:0)
只是为了记录,这是最快的方法,假设输入是无符号长整数或某种类型的int:
int count_digits( unsigned long n ){
unsigned long long quotient;
unsigned int ctDigits = 1;
while( n > 9 ){
ctDigits++;
quotient = (n >> 1) + (n >> 2);
quotient += (quotient >> 4);
quotient += (quotient >> 8);
quotient += (quotient >> 16);
quotient = quotient >> 3;
n -= ((quotient << 2) + quotient) << 1; // computes the remainder
}
return ctDigits;
}
任何使用除法(包括任何itoa /字符串转换)的解决方案都会慢得多,因为除法是一项昂贵的操作。在高速计算领域,分工是坏事,坏事。