用递归程序求解随机产生一个正整数n(n>=100000),确定n是否是它所有因子之和
来源:互联网 发布:聊天室挂机赚钱软件 编辑:程序博客网 时间:2024/06/05 08:34
用递归程序求解随机产生一个正整数n(n>=100000),确定n是否是它所有因子之和(完数)
了解什么是因子:因子就是所有可以整除这个数的数,不包括这个数自身,例如:6的因子为1,2,3。
完数:即某正整数的所有因子之和等于该数,即为完数。例:6的因子为1,2,3且6=1+2+3;即称6为完数。
进行分析,要求利用递归实现,递归是一种直接或间接引用自身的定义方法。一个合法的递归定义包括两部分:基础情况和递归部分。基础情况以直接形式明确列举新事物的若干简单对象,递归部分给出有简单(或较简单)对象定义新对象的条件和方法。
本题要求编写一个算法实现该功能,算法讲究性能,即时间复杂度和空间复杂度,一个好的算法不仅能够准确运行,而且他的时间复杂度很低。算法具有五个特性:a,有0个或者多个输入;b,至少有1个或者多个输出;c,算法具有确定性;d,算法的指令有限;e,算法具有可行性。
- 对于该问题,首先先求一个整数的所有因子,在程序中即对该数依次进行求模运算,结果为0则代表是因子。
/** * 求一个正整数的所有因子之和等于该数 * @author zclong * */public class test { public static void main(String[] args) { //产生随机数 int value = (int) (Math.random()*1000000); //计算因子之和 int sum = 0; //定义一个list数组存储因子 List<Integer> list = new ArrayList(); //对随机数进行遍历 long startTime = System.currentTimeMillis(); for (int j = 1; j <= value-1; j++) { if(value % j == 0) { list.add(j); sum = sum + j; } } long endTime = System.currentTimeMillis(); if(sum == value) { System.out.println("因子个数" + list.size() + ", 运行时间:" + (endTime-startTime) + "ms"); System.out.println(value + "是完数,其因子为" + list.toString()); }else { System.out.println("因子个数" + list.size() + ", 运行时间:" + (endTime-startTime) + "ms"); System.out.println(value + "不是完数,其因子为" + list.toString()); } }}
上面是普通的计算方法,从程序和结果可以看出,若是超过十万的整数,它将会计算十多万次,花费相当大的内存消耗和时间。
我们再用递归进行计算。
public class GetFactor { //产生随机数 final int value = (int) (Math.random()*10000); //计算因子之和 int sum = 0; //定义一个list数组存储因子 List<Integer> list = new ArrayList(); //执行次数 int count = 0; @Test public void test() { GetFactor factor = new GetFactor(); long startTime = System.currentTimeMillis(); factor.getFactor(1); // 调用执行方法,从1开始检验是否是因子 long endTime = System.currentTimeMillis(); System.out.println("运行时间:" + (endTime-startTime) + "ms"); } public void getFactor(int n) { count++; if(n > value-1) { if(sum == value) { System.out.println("因子个数" + list.size() + ", 执行次数" + count); System.out.println(value + "是完数,其因子为" + list.toString()); }else { System.out.println("因子个数" + list.size() + ", 执行次数" + count); System.out.println(value + "不是完数,其因子为" + list.toString()); } return; } else { if(value % n == 0) { list.add(n); sum = sum + n; } getFactor(n+1); } }}
上面的递归运算可以看出当进行运算的算超过10000。便出现了内存溢出的现象。
递归的缺点:
a.递归由于是函数调用自身,而函数调用是有时间和空间的消耗的:每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址以及临时变量,而往栈中压入数据和弹出数据都需要时间。->效率
b.递归中很多计算都是重复的,由于其本质是把一个问题分解成两个或者多个小问题,多个小问题存在相互重叠的部分,则存在重复计算,如fibonacci斐波那契数列的递归实现。->效率
c.调用栈可能会溢出,其实每一次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。->性能为了解决递归出现的问题,我们可以通过代数变换,减少子问题的个数。或者通过预处理,以空间换时间的方式进行处理。
我们选择预处理, 先对要求的正整数进行开平方根处理。
我们利用对该正整数求平方根来大大减少递归的次数,因为假设存在一个正整数num,使得num=k*M;且k不在(1,sqrt(num))之间,且M为正整数,那么M必在(1,sqrt(num))之间,否则k*M> sqrt(num)* sqrt(num),与num=k*M矛盾。所以我们只要求(1,sqrt(num))之间的因子即可,对应的因子也就出来了。
- 拿到要求的正整数的平方根之后,对其进行判断,当进行运算的数大于平方根数即结束,计算所有因子之和,若等于该数,即为完数;否则不断进行递归运算;
public class Test1 { List<Integer> list = new ArrayList(); int k = 0; int key =0; //产生随机数 int value = (int) (Math.random()*100000000); @Test public void factors(){ list.add(1); if(1 == value) return; int count1 = 1;// 1 与 N 必是(不包括N) final int sqrt_N = (int)Math.sqrt(value); // 进行求平方根 long startTime = System.currentTimeMillis(); recursive(sqrt_N, 2, 1);// 从2开始判断是否是因子,因为1是所有正整数的因子,因子之和的初始值sum=1 long endTime = System.currentTimeMillis(); System.out.println("所用时间为:" + (endTime - startTime) + "ms"); } public void recursive(int sqrt_N, int m, int sum) { k++; if(m > sqrt_N) { Collections.sort(list); // 对list数组进行排序 System.out.println("随机数为:" + value + ", 运行次数:" + k); System.out.println("其因子为" + list.toString() + ",因子个数:" + list.size()); if(sum == value) { System.out.println("其和为:" + sum + ", 是完数"); }else { System.out.println("其和为:" + sum + ", 不是完数"); } }else { if(0 == value % m) { // 判断是否整除为因子 list.add(m); key = value / m; // 求出另一个因子 list.add(key); sum = sum + m + key; // 求因子之和 recursive(sqrt_N,m + 1, sum); // 递归 }else { recursive(sqrt_N,m + 1, sum); // 递归 } } }}
7. 上述做法将一个1000000的数化为1000的数,这样做不仅不会使内存溢出,使得子问题的个数减少,而且节省了时间,大大降低了时间复杂度。
8. 通过递归划分子问题进行子问题的求解,使程序变得简单。但是若递归不当则会引起内存溢出,此时可以进行预处理或者减小子问题的个数,以空间换时间来实现,来解决递归内存溢出的问题。
- 用递归程序求解随机产生一个正整数n(n>=100000),确定n是否是它所有因子之和
- 数据结构与算法分析 2.20 编写一个程序来确定正整数N 是否是素数
- 一个正整数有可能可以被表示为n(n>=2)个连续正整数之和--算法求解
- 列出一个正整数表示成n(n>=2)个连续正整数之和的所有形式
- 面试题:输入一个正整数n,输出所有的连续正整数之和等于n的序列
- (c++)一个数如果恰好等于它的因子之和,这个数就称为"完数"。 例如,6的因子为1、2、3,而6=1+2+3,因此6是"完数"。 编程序找出N之内的所有完数,并按下面格式输出其因子
- 计算并输出给定正整数n的所有因子(不包括1和自身)之和
- 编写程序,判断用户输入的数字是否完全数.所谓“完全数”是指整数n的所有因子(不包括n)之和等于n自身。例如28的因子为1、2、4、7、14,而28=1+2+4+7+14,因此28是“完全数”。
- 求解一个正整数有可能可以被表示为 n个连续正整数之和
- C++ 判断n的因子之和是否等于n
- 一个正整数表示为n(n>=2)个连续正整数之和!
- 判断一个正整数是否是4的n次幂
- 如何设计一个高效算法从N个正整数中,随机选取n个不同的随机数 n<=N
- 将一个正整数n,拆分成连续的自然数之和,输出所有可能的情况
- 一个数如果恰好等于不包含它本身所有因子之和,这个数就称为"完数"。 例如,6的因子为1、2、3,而6=1+2+3,因此6是"完数"。 编程序找出N之内的所有完数,并按下面格式输出其因子
- 输入一个正整数N,要求求出它的所有加法分解式
- 输入一个正整数N,要求求出它的所有乘法分解式
- 递归方法求解n!
- Kafka学习整理九(集群的扩容)
- 设计模式之状态模式State
- 扫盲系列之JMS简介
- centos新服务器配置环境—
- PHP将数据库中的html标签转换到页面显示
- 用递归程序求解随机产生一个正整数n(n>=100000),确定n是否是它所有因子之和
- 【Android】混淆导致json解析出错
- Unity的Mono内存管理
- MySQL数据库优化的八种方式(经典必看)
- 查看进程使用端口号及结束进程 使用命令 sudo netstat -ntlp,可以查看到目前系统网络服务器的运行情况,然后使用 sudo kill -9 pid,结束进程。
- 输入接口返回值,然后得到一个含有所有参数名称的列表
- 如何添加Samba用户
- windows修改完环境变量立即生效
- 注册表是什么,原理是什么?mark undo