查找数字的商

时间:2016-12-05 17:15:51

标签: algorithm numbers

有一个给定号码N,我必须找出repetitive division和N给出商数的整数。

对于Ex:

N=8
Numbers Are 2 as: 8/2=4/2=2/2=1
            5 as  8/5=1
            6 as  8/6=1 
            7 and 8

我的诅咒:N/2+1N的所有数字都为我提供商1所以

Ans: N/2 + Check Numbers from (2, sqrt(N))

时间复杂度O(sqrt(N))

有没有更好的方法可以做到这一点,因为号码可以达到10^12并且可以有很多查询?

可以是O(1)还是O(40)(因为2 ^ 40超过10 ^ 12)

4 个答案:

答案 0 :(得分:0)

首先,您的算法不是O(sqrt(N)),因为您忽略了按每个选中的数字划分的次数。如果要检查的数字是k,则获得结果之前的分割数(通过上述方法)是O(log(k))。因此,复杂性变为N/2 + (log(2) + log(3) + ... + log(sqrt(N)) = O(log(N) * sqrt(N))

现在我们已经解决了这个问题,可以改进算法。请注意,通过重复划分,只有当1 k时,您才能获得k^t <= N < 2 * k^t的已检查号码t=floor(log_k(N))

k^t <= N < 2 * k^(t+1)时。请注意右侧的严格<

现在,为了弄清楚t,您可以使用Newton-Raphson方法或Taylor系列来非常快速地获得对数,并提到复杂性度量here。我们称之为C(N)。所以复杂性将是C(2) + C(3) + .... + C(sqrt(N))。如果您可以忽略计算log的费用,则可以将其设为O(sqrt(N))

例如,在上述情况下,N = 8:

  • 2^3 <= 8 < 2 * 2^3:1
  • floor(log_3(8)) = 18不满足3^1 <= 8 < 2 * 3^1:0
  • floor(log_4(8)) = 18不满足4^1 <= 8 < 2 * 4^1:0
  • 4其他来自5678的{​​{1}} 8来自这些号码。

请注意,我们不需要检查t=13,但我这样做是为了说明这一点。并且您可以验证4中的每个数字是否满足上述不等式,因此需要添加。

如果使用这种方法,如果计算对数的复杂度可以忽略不计,我们就可以消除重复的划分并将复杂度降低到[N/2..N]

答案 1 :(得分:0)

如果您希望每个查询O(1)查找,那么小于或等于10^12的自然哈希表将是其他自然权力的哈希表,不会大于2,000,000个元素;通过在1到1,000,000的基础上迭代来创建它,增加所看到的键的值;根1,000,000...10,001只需要平方;根10,000...1,001只需要立方体;之后,如前所述,最小的根最多可以有40次操作。

表格中的每个值都代表基本/电源配置的数量(例如,512 -> 2,对应于2^98^3。)

答案 2 :(得分:0)

用于验证功能和评估复杂性顺序的测试工具。

根据需要进行编辑 - 其维基

#include <math.h>
#include <stdio.h>

unsigned long long nn = 0;

unsigned repeat_div(unsigned n, unsigned d) {
  for (;;) {
    nn++;
    unsigned q = n / d;
    if (q <= 1) return q;
    n = q;
  }
  return 0;
}

unsigned num_repeat_div2(unsigned n) {
  unsigned count = 0;
  for (unsigned d = 2; d <= n; d++) {
    count += repeat_div(n, d);
  }
  return count;
}

unsigned num_repeat_div2_NM(unsigned n) {
  unsigned count = 0;
  if (n > 1) {
    count += (n + 1) / 2;
    unsigned hi = (unsigned) sqrt(n);
    for (unsigned d = 2; d <= hi; d++) {
      count += repeat_div(n, d);
    }
  }
  return count;
}

unsigned num_repeat_div2_test(unsigned n) {
  // number of integers that repetitive division with n gives quotient one.
  unsigned count = 0;

  // increment nn per code' tightest loop
  ...

  return count;
}

///

unsigned (*method_rd[])(unsigned) = { num_repeat_div2, num_repeat_div2_NM,
    num_repeat_div2_test};
#define RD_N (sizeof method_rd/sizeof method_rd[0])

unsigned test_rd(unsigned n, unsigned long long *iteration) {
  unsigned count = 0;
  for (unsigned i = 0; i < RD_N; i++) {
    nn = 0;
    unsigned this_count =  method_rd[i](n);
    iteration[i] += nn;
    if (i > 0 && this_count != count) {
      printf("Oops %u %u %u\n", i, count, this_count);
      exit(-1);
    }
    count = this_count;
    // printf("rd[%u](%u)      = %u.  Iterations:%llu\n", i, n, cnt, nn);
  }

  return count;
}

void tests_rd(unsigned lo, unsigned hi) {
  unsigned long long total_iterations[RD_N] = {0};
  unsigned long long total_count = 0;
  for (unsigned n = lo; n <= hi; n++) {
    total_count += test_rd(n, total_iterations);
  }
  for (unsigned i = 0; i < RD_N; i++) {
    printf("Sum rd(%u,%u) --> %llu.  total Iterations %llu\n", lo, hi,
        total_count, total_iterations[i]);
  }
}

int main(void) {
  tests_rd(2, 10 * 1000);
  return 0;
}

答案 3 :(得分:-1)

让我们看看号码可以达到10^12,你可以做的是为号码2 to 10^6创建,你可以创建40的数组,所以对于每个长度检查号码是否可以表示为i^(len-1)+ y,其中i介于2到10 ^ 6之间,而len介于140之间。

所以时间复杂度O(40*Query)