完美的数字表现

时间:2016-11-01 17:30:41

标签: java algorithm performance perfect-numbers

我有解决Kattis问题https://open.kattis.com/problems/almostperfect的解决方案。该解决方案已被接受,但运行时间过长(> 1.00秒)。 我尝试了一切来解决这个问题。我该怎么做才能进一步提高代码的性能?

import java.io.FileInputStream;
import java.util.Scanner;

import java.io.*;
import java.util.*;

public class almostperfect {

public static int perfect(int number){
    // 2 = perfect
    // 1 = almost perfect
    // 0 = not perfect
    int sum = 0;
    int b = 0;
    for(int i=1;i<number;i++)
    {
        if(number%i==0)
        {
            sum = sum + i;
        }
    }
    if(sum == number){
        b = 2;
    } else if(Math.abs(sum-number)<=2){
        b = 1;
    }

    return b;

}


public static void main(String[] args) 
{
    Scanner scan = new Scanner(System.in);
    ArrayList<Integer> input = new ArrayList<Integer>();
    int a;
    int status;
    while(scan.hasNextLong()){
        input.add((int) scan.nextLong());
    }
    for(int i=0; i<input.size(); i++){
    a = input.get(i);
    status = perfect(a);
    if(status==2){
        System.out.println(a+" perfect");
    } else if (status==1){
        System.out.println(a+" almost perfect");
    } else {
        System.out.println(a+" not perfect");
        }
    }

}}

2 个答案:

答案 0 :(得分:2)

当您计算number的除数时,您不必从1循环到number,而是循环到number的平方根。以100为例 - 如果2是100的dividor,那么是100/2。

int sum = 1;   //1 is always a divisor
int b = 0;
int sqr = (int)Math.sqrt(number);
for(int i=2;i< sqr;i++)
{
    if(number%i==0)
    {
        sum = sum + i;
        sum = sum + number/i;
    }
}
//Check what happens for sqr - if it's a divisor, add it only once
if (sqr * sqr == number)
    sum += sqr;

答案 1 :(得分:1)

你的代码没问题,找不到它实现的数字的因素的方法并不好。如果是一个因素,你需要比强力检查每个可能的小于数字的数字更聪明。

首先,显然1是总是一个因子,因为任何数字除以1而没有余数。而且,根据定义,数字本身不是一个因素。这限制了在范围(2 ... n-1)中找到的因素。

其次,如果你找到一个除数,那么被除数也是一个除数:

dividend = number / divisor -> implies: dividend is also a divisor

这意味着除数总是出现在中(被除数也是一个除数,使得该对)。必须考虑的一个例外是股息可能与股息相同(例如,数字= 9,除数= 3 - >除数= 3)。这可以被利用,导致:

第三,当从尽可能小的除数(2)开始测试时,你发现的第一个被除数是可能的最大除数,当你增加被测除数时,股息会逐渐减少。这意味着无需明确检查被视为被除数的除数。这意味着测试上限将是除数和被除数相等的位置,换句话说就是数字的根。

正如链接中的问题所述,数字可能在1 ... 1E9的范围内。你的蛮力方法需要10亿次测试1E9,而智能版本利用上述属性,只需要31621.这大约要快3倍!