美文网首页程序员
Java遍历完数的一些思考

Java遍历完数的一些思考

作者: lkee6760 | 来源:发表于2016-12-13 00:44 被阅读250次

题目:打印出1~10000以内所有的完数

1.分析1

  • 如果一个数恰好等于它的因子之和,则称该数为“完全数”。引用百度百科-完全数,如6=1+2+3
  • 不包括数本身的所有的因子之和等于这个数,所以1不符合要求;
  • 遍历所有2~10000的数,并且嵌套遍历0到该数范围内的所有预备因子,如果该数模预备因子等于0,则该预备因子为该数的因子,定义一个计数器,将所有因子累加,如果累加结果等于该数本身,即这个数为完数;
  • 为了便于比较运算效率,引入System.currentTimeMillis()方法记录遍历前后的系统当前毫秒值;

2.代码:

public class PerfectNumberDemo {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int num = 2; num <= 10000 ; num ++ ) {
            int sum = 0;
            for (int divisor = 1 ; divisor < num ; divisor ++) {
                if (num % divisor == 0 ) {
                    sum = divisor + sum;
                }
            }
            if (sum == num) {
                System.out.println(num);
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("遍历全部完数所使用的时间: " + (end - start) + " 毫秒");
    }
}
  • 运行结果:
    普通方法

3.一点思考

  • 判断10000这个数是否是完数需要遍历预备因子9999次,判断9999这个数是否是完全数需要遍历预备因子9998次,以此类推,根据等差数列求和公式需要遍历9998*(9999 + 2) / 2 = 49,994,999次,显然效率很低,需要进一步优化;
  • 经过分析,完数的最大因子不会超过他本身的一半,所以可以把divisor < num改成divisor <= num / 2
  • 继续分析,如果数num的第2因子divisor2,则(num / divisor2)也一定是num的因子,则(num / divisor2)到num之间一定不会有因子出现,下一步预备因子遍历范围缩小到divisor2 ~ (num / divisor2)
  • 继续,如果数num的第3个因子divisor3,则(num / divisor3)也一定是num的因子,则(nmu / divisor3)(num / divisor2)之间一定不会有因子出现,下一步预备因子遍历范围缩小到divisor3 ~ (num / divisor3),以此类推即可;
  • 将所有因子累加到计数器sum中,然后比较sum - num == num 即可,但是有个例外;
  • 例如num=16,第3个因子divisor3是4,则(num / divisor3)还是4,因子4不能重复计入计数器,所以需要使用if ··· else if ···语句判断两种情况,分别累加因子;

4.代码优化

public class PerfectNumberTest {
    public static void main(String[] args) {
        int count = 0;//定义一个计数器
        System.out.println("1~10000范围内的所有完数如下:");
        long start = System.currentTimeMillis();
        for (int num = 2; num <= 10000 ; num ++ ) {
            int sum = 0;//定义一个因子求和公式
            for (int divisor = 1 ; divisor <= num / divisor ; divisor ++) {
                if (num % divisor == 0 && divisor != num / divisor) {//若num开根号结果不是他的因子
                    sum = divisor + (num / divisor) + sum;//则num/divisor也一定是他的因子
                } else if (num % divisor == 0 && divisor == num / divisor) {//若num开根号的结果是他的因子
                    sum = divisor + sum;//则只把因子(num/divisor重复因子)赋值给sum
                }
            }
            if ((sum - num) == num) {//如果因子之和-该数等于该数,则这个数就是完数
                count ++;//计数器加一
                System.out.println("第 " + count +" 完数是: " + num);//输出完数
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("遍历全部完数所使用的时间: " + (end - start) + " 毫秒");
    }
}

5.执行结果

优化后的结果

6.说在后面

  • 本人电脑是13年购买,配置一般,所以结果仅说明运行效率问题;
  • 49,994,999+次遍历只用了400多毫秒,也就一眨眼的功夫,一般的算法优化对运行效率提升有限;
  • int类型取值范围到21亿,代码中有多个数累加求和,很可能求和结果超出int类型范围,影响运行结果,所以建议求完数的范围不要太大.

相关文章

  • Java遍历完数的一些思考

    题目:打印出1~10000以内所有的完数 1.分析1 如果一个数恰好等于它的因子之和,则称该数为“完全数”。引用百...

  • 二叉树的遍历

    前序遍历 python java 后序遍历 java python 中序遍历 java python

  • 函数_完数(Java实现)

    题目内容:一个正整数的因子是所有可以整除它的正整数。而一个数如果恰好等于除它本身外的因子之和,这个数就称为完数。例...

  • 从源码解读Java列表的遍历效率

    Java列表应该如何遍历效率更好? Java有三种遍历的方式: 普通for循环遍历(for) 增强型for循环遍历...

  • Java 语法小结

    Java的语法小结: 遍历Hash Map 直接遍历key: 遍历HashSet: Queue的使用 Java中Q...

  • java的iterator 遍历 list 和 map

    1 . java通过 iterator 遍历list 2 . 遍历 map

  • 101. Symmetric Tree

    Java ,中序遍历 优解,Java

  • 14 Java Set遍历的2种方法

    Java Set遍历的2种方法 Iterator迭代遍历

  • 完数

    所谓完数,就是除了它本身之外的因素之和,算法如下:

  • 完数

    1.问题描述 求某一范围内完数的个数如果一个数等于它的因子之和,则称该数为完数(或完全数)。例如,6的因子为1,2...

网友评论

    本文标题:Java遍历完数的一些思考

    本文链接:https://www.haomeiwen.com/subject/wzjvmttx.html