开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 24 天,点击查看活动详情
Day01 2023/02/27
难度:简单
题目1
从键盘输入一个整数,判断该数是否为素数(质数)。素数是指再大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
题目2
求解从2到20000的所有完全数,完全数是指它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。 例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。
示例1
输入: 3
输出: 3是素数
示例2
输入: 20000
输出: 6 2 8496 8128
说明: 输出了2~20000内的完全数
思路1
- 根据素数的定义可知,假设这个数是n,那么从2~(n-1)之间,任取一个数和n进行“n%该数”的操作,如果都不能整除的话,该数就为素数。
- 当然上述方法可以继续优化一下减少循环的次数,其实任何正整数的约数都是成对出现的,例如:12它的约数队分别是(1,12)(2,6) (3,4) ,所以我们只需要判断左边或者是右边的约数,是否满足素数的要求即可,左右队约数的分界线为自身的平方根。本题就采用这种优化过的方法。
思路2
- 这里求解完全数,最直接的方法就是暴力解法,根据完全数的定义,计算2~20000范围内每个数的真因子(即除了自身以外的约数)之和,如果等于本身,即该数就是完全数,接着输出它即可。
- 当然暴力解法的时间复杂度较高为,这里我们介绍一种优化过时间复杂度的一种方法,使用欧拉公式计算完全数。
欧拉公式说明:
-
如果是质数,且也是质数,那么便是一个完全数。
-
例如,是一个质数,也是质数,(是完全数。
-
例如,是一个质数,也是质数,(是完全数。
关键点
- 第一个问题也是求解第二个问题的一部分及判断该数是否为素数(质数)
算法实现
c++代码实现-优化后的方法
#include <cmath>
#include <iostream>
using namespace std;
//问题一:判断是否为素数(质数)
bool is_prime(int p) {
for (int i = 2; i <= sqrt(p); i++) //判断是否有除了1和自生的因数(约数)
if (p % i == 0)
return false;
return true;
}
//问题二:求完全数
// 方法:欧拉公式
// 如果p是质数,且2^p-1也是质数,那么(2^p-1)X2^(p-1)便是一个完全数
int main() {
int n;
cin >> n;
for (int p = 2; p <= n; p++) { //1肯定不是完全数
int t = pow(2, p) - 1;
if (is_prime(p) && is_prime(t)) { // 调用is_prime方法,判断是否满足欧拉方程的要求,计算完全数
int perfect_num = pow(2, p - 1) * t;
if (perfect_num <= n)
cout << perfect_num << ' ';
else
break; //当大于n时就跳出循环,大大降低了循环次数
}
}
}
判断是否为素数:
- 时间复杂度 ---循环m次,其中m为该数的平方根
- 空间复杂度 ---都是常数级的辅助变量,除此没有额外的辅助空间
求完全数:
- 时间复杂度 --- 判断是否为素数要,循环m次,其中m为该数的平方根 ,在此基础上,判断范围内的完全数,外层还有一个for循环,在最坏情况下循环n次,其中n为范围大小
- 空间复杂度 ---都是常数级的辅助变量,除此没有额外的辅助空间
总结
这两题,都介绍了最常规的方法,和经过优化后的方法,如果实在不明白优化后的方法,也可以使用常规方法。