(树的创建未懂)【蓝蓝计算机考研算法】-day19-完全数、二叉树深度

89 阅读3分钟

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);
}

运行结果

image.png

复杂度

  • 时间复杂度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,#,#}(先序),那么如下图:
image.png
示例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;
}

运行结果

image.png

复杂度

  • 时间复杂度O(n)--- 递归访问二叉树所有节点 ,其中n为节点总数
  • 空间复杂度O(n)--- 最坏情况下二叉树呈现链状,递归栈深度等于二叉树节点数n