将完美数字检查优化为O(sqrt(n))

时间:2017-11-07 22:14:41

标签: time time-complexity pascal freepascal asymptotic-complexity

程序的一部分我检查输入数字是否是完美数字。我们应该找到一个在O(sqrt(n))中运行的解决方案。我的程序的其余部分在恒定的时间运行,但这个功能阻止了我。

function Perfect(x: integer): boolean;
var
  i: integer;
  sum: integer=0;
begin
  for i := 1 to x-1 do
    if (x mod i = 0) then
      sum := sum + i;
    if sum = x then
      exit(true)
    else
      exit(false);
end;

这在O(n)时间运行,我需要将其减少到O(sqrt(n))时间。

这些是我提出的选项:

(1)找到一种方法使for循环从1到sqrt(x)......

(2)找到一种检查不使用for循环的完美数字的方法......

有什么建议吗?我感谢任何提示,技巧,指导等。:)

1 个答案:

答案 0 :(得分:1)

您需要迭代循环而不是for i := 1 to x-1而是for i := 2 to trunc(sqrt(x))。 最高整数除数是x但我们在寻找完美数字时不会考虑它。我们将sum加1(或者用1初始化 - 而不是0)。

为此目的,代码if (x mod i = 0) then sum := sum + i;可以转换为:

if (x mod i = 0) then
  begin
    sum := sum + i;
    sum := sum + (x div i);
  end;

所以我们得到以下代码:

function Perfect(x: integer): boolean;
var
  i: integer;
  sum: integer = 1;
  sqrtx: integer;
begin
  sqrtx := trunc(sqrt(x));
  i := 2;
  while i <= sqrtx do
    begin
    if (x mod i = 0) then
      begin
        sum := sum + i;
        sum := sum + (x div i) // you can also compare i and x div i 
                               //to avoid adding the same number twice 
                               //for example when x = 4  both 2 and 4 div 2 will be added
      end;
    inc(i);
    end;
    if sum = x then
      exit(true)
    else
      exit(false);
end;