一个显而易见的解决方案是:
int n = 2134;
while(n > 9)
n /= 10;
它需要线性时间。我们能做得更快吗?
这比线性时间更快吗:
char s[100];
sprintf(s, "%d", n);
n = s[0]-'0';
还有其他方法吗(效率是主要考虑因素)?
我看了这个,但我只需要找到第一个数字。
(我也不理解答案。)
有些处理器拥有能够快速计算数字“大小”的指令(参见http://en.wikipedia.org/wiki/Leading_zero_count)。这可以用来快速选择10的幂,并将其除以它,而不是重复地除以10。
假设你有一个函数clz
,它可以计算一个数字在二进制表示中前导零位的数量(0…32)。然后,您可以使用查找表,为每个前导零位数提供适当的10的幂。
uint32_t powers_of_10[33] = {
1000000000, 1000000000,
100000000, 100000000, 100000000,
10000000, 10000000, 10000000,
1000000, 1000000, 1000000, 1000000,
100000, 100000, 100000,
10000, 10000, 10000,
1000, 1000, 1000, 1000,
100, 100, 100,
10, 10, 10,
1, 1, 1, 1, 1
};
int CalcFirstDecimalDigit(uint32_t x)
{
int leading_zeros = clz(x);
x /= powers_of_10[leading_zeros];
if (x >= 10)
return 1;
else
return x;
}
uint32_t powers_of_10[33]
。 - chux - Reinstate Monica例如,对于32位无符号数:
步骤1:通过二分查找确定该值在以下哪个区间内:
0 .. 9
10 .. 99
100 .. 999
1000 .. 9999
10000 .. 99999
100000 .. 999999
1000000 .. 9999999
10000000 .. 99999999
100000000 .. 999999999
1000000000 .. 4294967295
最多需要4次比较。
步骤2:
然后通过一次除法计算出前导数字。
我相信,sprintf函数(我猜测是这个函数)的速度会显著变慢。你可以进行一些优化来减少除法操作的次数(这通常是几乎所有处理器上最慢的指令之一)。
因此,可以尝试如下操作:
while(n > 10000)
n /= 1000;
while(n >= 9)
n /= 10;
sprintf
函数。因为整个数字都被打印出来,所以会搜索所有数字,因此也不会更快。x
位数的数字,它的十进制对数介于x
和x+1
之间。但由于浮点误差,在某些情况下这种方法并不能正常工作。此外,请考虑到执行浮点运算比执行整数运算要慢。sprintf
或log()
更快,甚至可能比MrSmith42的答案还要快。 - cmaster - reinstate monica这是一种二分查找的变体。像二分查找一样,它的时间复杂度为O(log n)。但它的速度快不快取决于你能够多快地进行整数除法。
if (n >= 100000000)
n /= 100000000
if (n >= 10000)
n /= 10000
if (n >= 100)
n /= 100
if (n >= 10)
n /= 10
只需这样做:
//Shashank Jain
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int num,fdigit;
cin>>num;
if(num<0)
num*=-1;
int l=log10(num); // l = (length of number -1)
fdigit=num/pow(10,l);
cout<<fdigit<<endl;
return 0;
}
int FirstDigit ( int Number ) {
// to obtain the <number of digits -1> use this math formula:
int DigitsInNumber = (int) lg(Number);
long TenExpon = pow(10, DigitsInNumber);
return (Number / TenExpon); //first digit
}
also: lg(n) = ln(n) / ln(10);
for(int i=0; i<n; i++)
{
e=5; //Specify the number of digits in the number OR Exponential value of 10
while(e>=0)
{
tenp=pow(10,e); //#include <math.h>
if(arr[i]/tenp!=0)
{
q[i][e]=arr[i]/tenp%10;
}
e--;
}
}
然而,这段代码的复杂度应该是O(n ^ 2),这是不可取的。
你的第一个解决方案(假设已知 n >= 0)几乎是最优的,我认为只有通过使用内联汇编语言才能实现实质性改进。但这只有在处理数百万个这样的数字时才值得。
你的第二个解决方案 -- 怎么说呢? -- 更像是一种 Java 风格的方法:性能?哦,谁在乎...
sprintf
而不是scanf
? - Mats Peterssonsscanf()
应该真的改成snprintf()
吗? - user529758digits = floor(log10(n)); firstDigits = n/10^digits;
和将double
类型强制转换为整型所组成的代码。 - millimoosesizeof(int)==4
的平台上最多有10个十进制数字),也可以被视为是常数的。仅仅说“线性的”可能听起来比实际情况更糟糕... - David Rodríguez - dribeas