JAVA求解完美数

本文介绍了完美数的概念,即一个数的真因子之和等于它本身的数。讲解了使用JAVA求解完美数的思路,包括分解因式、求真因数和的步骤。文章通过分析难点,提出通过因式分解求解真因数和的方法,并提供了相关代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


1、概念

首先我们理解一下,什么叫做完美数?完美数又称为完数,如果一个数n,它的所有真因子之和,等于它本身,那么n就被称之为完数。例如以下几个完数:

6 = 1 + 2 + 3
28 = 1 + 2 + 4 + 7 + 14
496 = 1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248
按照完数的定义,其实用程序求解完数并不是太难,先求解出这个数的所有真因子,然后相加,判断是否等于它本身即可。但是,在这个数很小的时候,没有什么问题,一旦这个数字超过一定的数值,那么问题就来了,程序的执行效率就会变得低下。

我们优化程序的算法逻辑,往往会考虑一个问题,怎么高效的利用计算机的特性?在它所定义的算法中,有没有大量重复的无用功呢?沿着这样的思路去考虑这个问题,我们会很快得到另外的一种解决方案。


2、说明

2.1 分析

在这里,我们会不会很容易就想到,之前我们提到过的分解因式?是的,在解决完美数的时候,我们会用到分解因式。一般来说,求解完美数会经过三个步骤:

1. 求出一定数目的质数表

2. 利用质数表求指定数的因式分解

3. 利用因式分解求所有真因数和,并检查是否为完美数

2.2 难点

初看之下,第一步和第二步是没什么问题的,我们在前面的两篇文章中已经探讨过了,不清楚的同学可以查看。

重点是在第三步,如何求真因数和?方法很简单,要先知道将所有真因数(有不清楚真因数概念的同学,去看看)和加上该数本身,会等于该数的两倍(有些同学不知道,现在应该也知道了吧?),例如:

2 * 28 = 1 + 2 + 4 + 7 + 14 + 28

    事实上,这段等式可以转换为:(代码输入错误,我用截图好了)


发现没有?2和7都是因式分解得到的,那么,程序是不是有了简化的地方?

    2.3 结论

    只要求出因式分解,就可以利用循环求得等式后面的值,将该值除以2就是真因数和了;等式后面第一眼看时可能想到使用等比级数公式来解,不过会使用到次方运算,可以在进行读取因式分解阵列时,同时计算出等式后面的值。

3、代码

import java.util.ArrayList;
// 求解完美数
public class PerfectNumber {
	// 传入一个值,求解至少多少个完美数
    public static int[] lessThan(int number) {
        int[] primes = Prime.findPrimes(number);

        ArrayList list = new ArrayList();
        
        for(int i = 1; i <= number; i++) { 
            int[] factors = factor(primes, i); 
            if(i == fsum(factors)) 
                list.add(new Integer(i));
        } 

        int[] p = new int[list.size()];
        Object[] objs = list.toArray(); 
        for(int i = 0; i < p.length; i++) {
            p[i] = ((Integer) objs[i]).intValue();
        }
        
        return p;
    }
    
	// 分解因式
    private static int[] factor(int[] primes, int number) { 
        int[] frecord = new int[number];
        int k = 0;
        
        for(int i = 0; Math.pow(primes[i], 2) <= number;) { 
            if(number % primes[i] == 0) { 
                frecord[k] = primes[i]; 
                k++; 
                number /= primes[i]; 
            } 
            else 
                i++; 
        } 

        frecord[k] = number; 

        return frecord; 
    } 

	// 因式求和
    private static int fsum(int[] farr) { 
        int i, r, s, q; 

        i = 0; 
        r = 1; 
        s = 1; 
        q = 1; 

        while(i < farr.length) { 
            do { 
                r *= farr[i]; 
                q += r; 
                i++; 
            } while(i < farr.length - 1 &&
                    farr[i-1] == farr[i]); 
            s *= q; 
            r = 1; 
            q = 1; 
        } 

        return s / 2; 
    }
    
    public static void main(String[] args) {
        int[] pn = PerfectNumber.lessThan(1000);
     
        for(int i = 0; i < pn.length; i++) {
            System.out.print(pn[i] + " ");
        }
        
        System.out.println();
    }
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值