26、完全数,又称完美数或完备数,是一些特殊的自然数。
它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:28,它有约数1、2、4、7、14、28,除去它本身28以外,其余5个数相加,1+2+4+7+14=28.
输入n,请输出n以内(含n)完全数的个数。
数据范围:1 <= n < 5*105
输入描述:
输入一个数字n
输出
输出不超过n的完全数的个数
示例1
输入:
1000
输出:
3
思路
思路一:
- 利用双层for循环,外层循环判断2到n,内层判断其是否为完全数,若是,则计数器+1。
- 判断因子:循环遍历1到n-1,对其取余,看余数是否为0,为0则表示能除尽,即是因子数。
思路一的优化法 : - 计算1~n范围内每个数的真因子(即除了自身以外的约数)之和,如果等于本身,即该数就是完全数,接着计数器加1,最后返回计数器结果即可。
- 思路一中外层循环控制被除数,内层循环控制除数,并判断该除数是否为真因数。
- 虽然思路一中采用的是暴力解法,但是优化了内层循环的循环次数。当
j <= n/2时即可退出循环。 因为没有大于自身 1/2 的真因子(这是个数学问题)
思路二,采用欧拉公式计算,[详情可参考链接](HJ56 完全数计算 - 掘金 (juejin.cn))
具体实现
//完全数
#include <stdio.h>
int main()
{
int n, sum = 0, count = 0;//n代表输入的数范围,sum是表示一个数的真因子的和,count是累计是完全数的
scanf_s("%d", &n);
for (int i = 2; i <= n; i++) {//外层循环2到n
for (int j = 1; j < i; j++) {//内层为判断i是否为完美数
if (i % j == 0)//因子数相加
sum += j;
}
if (sum == i) {
count++;//判断因子数是否等于本身,若相等则计数器+1
}
sum = 0;//判断结束,sum置零重新循环加和
}
printf("%d", count);
return 0;
}
//完全数_优化法 暴力解法
//完全数_优化法 暴力解法
#include <stdio.h>
int main()
{
int n;
scanf_s("%d", &n);//输入n
int count = 0; //计数器
for (int i = 2; i <= n; i++) {//1肯定不是完全数
int sum = 1; //累加器,1是任何数的约数
for (int j = 2; j <= n / 2; j++) {//大于自身1/2的约数是不存在的
if (i % j == 0 && i != j) {
sum += j; //i为被除数,j为除数。真因子不包括自生
}
}
if (sum == i) {
count++; //如果是完全数就加1
}
}
printf("完全数个数为:%d", count);
}
运行结果
复杂度
- 时间复杂度O(n^2) ---双层嵌套循环,其中n为数值大小,实际循环次数要小于n^2
- 空间复杂度 O(1) --- 没有额外的辅助空间
27、输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1。
数据范围:节点的数量满足 0<=n<=100,节点上的值满足0<=val<=100
进阶:空间复杂度 O*(1),时间复杂度O(n)
假如输入的用例为{1,2,4,#,#,5,7,#,#,#,3,#,6,#,#}(先序),那么如下图:
示例1
输入:1 2 4 # # 5 7 # # # 3 # # # 6 # #
输出:4
示例2
输入:
{}
返回值:
0
思路
计算二叉树的深度属于二叉树的基本操作,一般使用基于DFS(深度优先算法)来计算二叉树深度!
- 这里递归加1,可以理解为递归计算的是路径上的边,而深度计算的是 边 上的节点,所以要加1。
- 创建二叉树时,本题采用的是先序遍历的序列(根左右)来创建的。
具体实现
#include <iostream>
#include <string>
using namespace std;
// 定义二叉树节点
typedef struct BiTNode {
string data; // 数据域
BiTNode *left, *right; // 左右节点
BiTNode(string val) : data(val), left(nullptr), right(nullptr){};
} BiTNode, *BiTree;
// 创建二叉树 (采用先序遍历的方式)
void CreateBTree(BiTree &T) {
string val; // 节点数据
cin >> val;
if (val == "#") T = nullptr; // val等于#代表该节点不存在
else {
T = new BiTNode(val); // 申请新节点
CreateBTree(T->left);
CreateBTree(T->right);
}
}
// 计算二叉树深度 (属于基操)
int TreeDepth (BiTree T) {
if (!T) return 0;
int LDepth = TreeDepth(T->left);
int RDepth = TreeDepth(T->right);
return LDepth > RDepth ? LDepth + 1 : RDepth + 1;
}
int main() {
BiTree T;
CreateBTree(T); // 创建二叉树
int deep = TreeDepth(T); // 计算二叉树深度
cout << "深度为:" << deep;
}
运行结果
复杂度
- 时间复杂度O(n)--- 递归访问二叉树所有节点 ,其中n为节点总数
- 空间复杂度O(n)--- 最坏情况下二叉树呈现链状,递归栈深度等于二叉树节点数n