优化递归问题以计算超级数字

时间:2019-06-23 15:03:10

标签: c++ recursion

我已经正确编写了用于获取大量(长而长)的超数字的程序,但是由于超时和中止调用,似乎无法通过某些情况。请提出一些优化措施以改善程序的运行时间:

int superDigit(long long m) {
    int d=countDigit(m);
    if(d==1){
        return m;
    }
    long s=sumDigit(m);
    return superDigit(s);

}

//utility functions to calculate digit count and sum of digits

int countDigit(long long n) 
{ 
    int count = 0; 
    while (n != 0) { 
        n = n / 10; 
        ++count; 
    } 
    return count; 
}

long sumDigit(long long n) 
{ 
    long sum = 0; 
    while (n != 0) {
        sum += n % 10; 
        n = n / 10;  
    } 
    return sum; 
}

理论:超数字由以下规则定义:

  • 如果x只有1位数字,则其超级数字为x
  • 否则,x的超数字等于x的数字之和的超数字

例如:

  1. super_digit(9875):9 + 8 + 7 + 5 = 29,然后
  2. super_digit(29):2 + 9 = 11,然后
  3. super_digit(11):1 +1 = 2,然后
  4. super_digit(2):= 2

3 个答案:

答案 0 :(得分:4)

每个superDigit调用仅对数字循环一次,并避免递归可以使速度更快。像这样:

long long superDigit(long long m) {
    long long sum;
    while(true) {
        sum = 0;
        while(m != 0) {
            sum += m % 10;
            m /= 10;
        }
        if(sum >= 10)
            m = sum;
        else
            break;
    }
    return sum;
}

如果您需要支持重复序列,例如593次10次(对于long long而言通常太大),则可以添加一个包装器,如下所示:

long long superDigit(long long m, int times) {
    long long r = superDigit(m) * times;
    if(r >= 10) r = superDigit(r);
    return r;
}

对于足够小以适合long long的数字,您可以检查其是否有效。示例:

superDigit(148148148) == superDigit(148, 3)

如果需要支持不是 重复序列的大数字,则可以添加另一个重载,将数字作为std::string

long long superDigit(const std::string& m) {
    long long sum = 0;  
    for(auto d : m) sum += d - '0';
    if(sum >= 10) return superDigit(sum);
    return sum;
}

您可以检查它是否也获得了与以前的重载之一相同的结果:

superDigit(593, 10) == superDigit("593593593593593593593593593593")

答案 1 :(得分:0)

我认为您正在中止要求m值!如果m的值为0,则递归将继续存在。而且,如果m的值可以为负,那么也要注意负值的问题。

请检查!

int superDigit(long long m) {
    if(m<=9)return m; //  handling case 0
    int d=countDigit(m);
    if(d==1){
        return m;
    }
    long s=sumDigit(m);
    return superDigit(s);

}

答案 2 :(得分:0)

您的代码有一个'0'问题。它进入一个无限循环,如果调用堆栈溢出(如果编译器没有消除尾部递归的话),该循环将终止。 完全不需要数字计数助手功能

int superDigit(long long m) {
  if(m<10){
    return m;
  }else{
    int s = 0;
    do {
      s += m % 10;
      m = m / 10;
    }while (m > 0);
    return superDigit(s);
  }
}

您可以通过将整个过程放在一个循环中来消除递归。

int superDigit(long long m) {
  while (m >9){
    int s = 0;
    do {
      s += m % 10;
      m = m / 10;
    }while (m > 0);
    m = s;
  }
  return m;
}

但是递归看起来有些自我解释,现代编译器也应该能够消除尾递归。