计算整数中不同数字的最有效方法是什么

时间:2014-09-14 09:56:27

标签: c algorithm optimization distinct-values

数字可以是1到10 15 。 我正在使用此代码,但它已经没时间了。

int distinct(long long int a)
{
    int ele[10]={0},i,c=0;

    if(a==0) return 1;
    if(a<0) a=a*-1;

    while(a)
    {
        int t=a%10;
        ele[t]=1;
        a=a/10;
    }

    for (i=0;i<10;i++)
        if (ele[i])
            c++;

    return c;
}

2 个答案:

答案 0 :(得分:1)

结合各种想法并解决UB。

IMO,怀疑OP遗漏了一些导致缓慢的重要原因。

// 1 to 10^15 only
int distinct_fast(long long int a) {
  int ele[10]={0},i,c=0;

  do {
    ele[a%10]=1;
    a /= 10;
  } while(a);

  i=10-1;
  do {
    c += ele[i]; // @barak manos
    }
  } while (i-- > 0);
  return c;
}

// entire unsigned long long range method 1
int distinct_complete1(unsigned long long int a) {
  ... // same code as above

// entire long long range method 2
int distinct_complete2(long long int a) {
  int ele[10]={0},i,c=0;

  // Use (-) numbers as there are more (or the same) number of (+) numbers
  if (a > 0) a = -a;   

  do {
    ele[-(a % 10)] = 1;
    a /= 10;
  } while(a);

  // same as above
  ...

OP探索的想法:

unsigned char ele[10]={0};   // smaller flags

do {
  if (ele[a%10]++ == 0) c++;
  a /= 10;
} while(a);
// This eliminates need for following loop to add `ele[]`

// Invoke some strategy so when when a is small enough, 
// use `long` ops rather than `long long`
if (a > 1000000000) {
  for (i=6; i-- > 0; ) {
    if (ele[a%10]++ == 0) c++;
    a /= 10;
  } 
}
unsigned long b = a;  
do {
  if (ele[b%10]++ == 0) c++;
  b /= 10;
} while(b);

int distinct_complete3(unsigned long long int a) {
  unsigned char ele[10]={0};
  int c = 0;
  do {
    if (ele[a%10]++ == 0) c++;
    a /= 10;
  } while(a);
  return c;
}

答案 1 :(得分:0)

几种可能的优化:

  • 你可以用模数换取乘法,通常要快得多:q= a / 10; m= a - 10 * q;

  • 你可以通过将所有标志打包在一个整数中来避免最后的计数循环,让mask;用mask= 0初始化它;每当您找到一个数字(m)时,请用mask|= (1 << m)标记;最后,计数将由bits[mask]给出,其中bits是一个向量,包含从01023=2^10-1的所有整数的预先计算的计数。

    int distinct(long long int a) 
    {  
        int mask= 0;
        while (a)
        {
            int q= a / 10, m= a - 10 * q;
            mask|= 1 << m;
            a= q;
        }
    
        static short bits[1024]= { 0, 1, 1, 2, 1, 2, 2, 3, ...}; // Number of bits set
        return bits[mask];
    }
    

更好的是,您可以使用组中的数字,例如三个。而不是转换为基数10,转换为基数1000.并且对于每个基数1000&#34;数字&#34;,计算标记组成十进制数字的相应掩码(例如,535产生掩码{{ 1}})。

这应该快三倍。无论如何,应该添加对前导零的一些关注,例如为前导三元组提供一个独特的掩码阵列(1<<5 | 1<<3 | 1<<5 = 40 vs ..1)。

001

使用静态数组确保它们一次性加载。