redbook的判断完美数
小红书8-27笔试第一个编程题
- 题目
- 思路
- 代码
题目
题目大致是先输入一个整数n,再输入n个整数。
需要一个一个判断这n个整数是否为完美数,如果是就打印YES,如果不是就打印NO。
完美数的定义是是否存在一个公差为1的等差数列的乘积等于这个数x,并且这个等差数列的长度还必须大于等于3。
思路
首先是等差数列的长度是大于等于三的所以最小的完美数就是123即6,那么只要有数小于6就可以直接返回false了,那么大于6的数呢?首先呢我们可以使用暴力枚举的方法,我们仔细观察一下题目可以发现这道题有三个变量需要考虑,一是等差数列的长度k,二是等差数列的头start是哪里,三是等差数列的乘积total和x的比较。首先我们解决等差数列长度的问题,因为等差数列的长度必须大于等于三所以我们以3开始一个循环,在固定了等差数列的长度后我们不用继续计算第二个和第三个变量。在我们知道了等差数列的长度后那么这个等差数列的最小乘积不也就知道了即从1开始乘起也就是长度k的阶乘,如果阶乘都已经大于x了我们就可以直接退出了,因为前面的长度没有得到答案才来到现在的长度并且后面长度的阶乘更是大于现在长度的阶乘所以我们就可以直接退出循环了。那么在阶乘小于x后我们就需要再来判断start和end了,这两个值就好判断了我们直接使用两层循环,外层从1开始遍历从而固定start,内层从让total从start开始乘起,然后判断和x的关系。如果等于x就返回true,大于x就break进行下一次循环。
代码
#include <iostream>
using namespace std;/*** 判断一个数是否为完美数* 完美数定义:可以表示为一个长度至少为3、公差为1的等差数列的乘积* * @param x 要判断的数字* @return 如果是完美数返回true,否则返回false*/
bool isPerfectNumber(long long x) {// 如果x小于6,直接返回false,因为最小的完美数是1*2*3=6if (x < 6) return false;// 从k=3开始尝试不同的序列长度for (int k = 3; ; k++) {// 计算k的阶乘,这是k个连续整数的最小可能乘积(当n=1时)long long fact = 1;for (int i = 1; i <= k; i++) {// 防止阶乘计算溢出:如果fact已经大于x除以i的值,说明阶乘会超过xif (fact > x / i) {fact = x + 1; // 设置为x+1,表示已经超过xbreak;}fact *= i;}// 如果k!已经大于x,那么更大的k更不可能,直接退出循环if (fact > x) break;// 对于当前k,尝试不同的起始值nfor (long long n = 1; ; n++) {long long p = 1; // 用于存储连续k个整数的乘积// 计算n*(n+1)*...*(n+k-1)的乘积for (int i = 0; i < k; i++) {long long factor = n + i; // 当前因子// 防止乘积溢出:如果p已经大于x除以因子的值,说明乘积会超过xif (p > x / factor) {p = x + 1; // 设置为x+1,表示已经超过xbreak;}p *= factor; // 乘以当前因子}// 如果乘积等于x,找到了完美数if (p == x) return true;// 如果乘积已经大于x,增加n只会使乘积更大,所以退出内层循环if (p > x) break;}}// 所有可能的k和n都尝试过了,没有找到符合条件的序列return false;
}int main() {long long x;cout << "请输入一个数字: ";cin >> x;if (isPerfectNumber(x)) {cout << "true" << endl;} else {cout << "false" << endl;}return 0;
}