有兄弟学Java,问我怎么算3000以内的亲密数(亲密数是什么?A的因子之和等于B,B的因子之和等于A,A与B互为亲密数)。
记得当初有一版标准答案:
class Qinmin1{
static void fun1(int range) {
long start = System.currentTimeMillis();
for(int i=1;i<range;i++){
int aSum=0,bSum=0;
for(int a=1;a<=i/2;a++){
if(i%a==0){
aSum+=a;
}
}
for(int b=1;b<=aSum/2;b++){
if(aSum%b==0){
bSum+=b;
}
}
if(bSum==i&&i<aSum){
System.out.println(i+" 和 "+aSum+" 互为亲密数!");
}
}
System.out.println("Qinmin1.fun1运行用时:"+(System.currentTimeMillis()-start)+"ms.");
}
}
但是标准答案也不一定是完美的,当题目要求计算的不是3000,而是2700,或者5100时,会出现一个问题:
220 和 284 互为亲密数!
1184 和 1210 互为亲密数!
2620 和 2924 互为亲密数!
Qinmin1.fun1运行用时:31ms.
220 和 284 互为亲密数!
1184 和 1210 互为亲密数!
2620 和 2924 互为亲密数!
5020 和 5564 互为亲密数!
Qinmin1.fun1运行用时:70ms.
发现了吗?2924和5564是超出了范围的。于是代码修改为
class Qinmin2{
static void fun2(int range) {
long start = System.currentTimeMillis();
for(int i=1;i<range;i++){
int aSum=yinziSum(i);
if(yinziSum(aSum)==i&&i<aSum&&aSum<range){
System.out.println(i+" 和 "+aSum+" 互为亲密数!");
}
}
System.out.println("Qinmin3.fun3运行用时:"+(System.currentTimeMillis()-start)+"ms.");
}
private static int yinziSum(int num){
int sum = 0;
for(int i=1;i<=num/2;i++){
if(num%i==0){
sum+=i;
}
}
return sum;
}
}
虽然代码风格跨度有点大,但是抽取重复代码不应该是一个资深菜鸟应该做到的吗?这不是重点,判断条件才是。
至此代码写完了。但是还有问题,一些数字的因子和被计算了不止一遍,这怎么行,性能啊!!!
为了只计算一次,再次修改代码:
class Qinmin3{
static void fun3(int range){
long start = System.currentTimeMillis();
Map<Integer,Integer> yinziMap = new HashMap<>();
for(int i=1;i<range;i++){
yinziMap.put(i,yinziSum(i));
}
for (Integer key:yinziMap.keySet()) {
if(Objects.equals(yinziMap.get(yinziMap.get(key)), key)
&&key.compareTo(yinziMap.get(key))<0){
System.out.println(key+" 和 "+yinziMap.get(key)+" 互为亲密数!");
}
}
System.out.println("Qinmin2.fun2运行用时:"+(System.currentTimeMillis()-start)+"ms.");
}
private static int yinziSum(int num){
int sum = 0;
for(int i=1;i<=num/2;i++){
if(num%i==0){
sum+=i;
}
}
return sum;
}
}
用一个map将每个数字的因子之和装起来,不就能只计算一次了吗?用空间换时间啊。虽然对于刚入门的菜鸟来说有点超纲,但性能大大提高了,至少节省一半运行时间。