我有解决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");
}
}
}}
答案 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倍!