PAT_甲级_1110 Complete Binary Tree (25point(s)) (C++)【完全二叉树】

目录

1,题目描述

题目大意

2,思路

数据结构

算法

3,AC代码

4,解题过程

第一搏

第二搏

第三搏

第四搏


1,题目描述

Sample Input 1:

9
7 8
- -
- -
- -
0 1
2 3
4 5
- -
- -

 

Sample Output 1:

YES 8

Sample Input 2:

8
- -
4 5
0 6
- -
2 3
- 7
- -
- -

 

Sample Output 2:

NO 1

题目大意

判断一棵树是否为完全二叉树(允许最后一层有空节点,且最后一层的节点需要按照自左向右的顺序排列),是则输出最后一个节点的index,不是则输出根节点的index;

 

2,思路

借鉴了这位大佬的思路!@程勇uestc【PAT甲级1110 Complete Binary Tree (25 分)题解】

数据结构

  • struct node{
        int left, right;
    }tree[25]树的存储方式;
  • bool notRoot[N]:判断节点i是否为根节点,false是、true否;

算法

  1. 接收数据构建树,并判断哪些节点不是根节点
  2. 确定根节点:                                          
  3. DFS遍历树,并记录树可达的最远距离maxDep和最远节点lastNode(利用二叉树数组表示的特性,假设下标从1开始:根节点i,其孩子在数组中的位置分别为:左孩子2*i,右孩子2*i+1。这里不真实声明数组,而只是记录数组的最大长度,即最后一个节点)
  4. (下标从1开始)若最后一个节点位置为N,即说明为完全二叉树:

 

3,AC代码

#include<bits/stdc++.h>
using namespace std;
struct node{
    int left, right;
}tree[25];
int N, root, lastNode, maxDep = 0;
void dfs(int start, int dep){
    if(start == -1)
        return;
    if(dep > maxDep){       //寻找最远的一个节点
        maxDep = dep;
        lastNode = start;
    }
    dfs(tree[start].left, 2 * dep);
    dfs(tree[start].right, 2 * dep + 1);
}
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    cin>>N;
    bool notRoot[N], flag = false;
    string s1, s2;
    node n;
    fill(notRoot, notRoot + N, false);  // !!!注意初始化
    for(int i = 0; i < N; i++){         //节点编号从0开始
        cin>>s1>>s2;
        n.left = (s1 == "-" ? -1 : stoi(s1));
        n.right = (s2 == "-" ? -1 : stoi(s2));
        if(n.left != -1) notRoot[n.left] = true;
        if(n.right != -1) notRoot[n.right] = true;
        tree[i] = n;
    }
    for(int i = 0; i < N; i++){         //确定根节点
        if(notRoot[i] == false){
            root = i;
            break;
        }
    }
    dfs(root, 1);
    if(maxDep == N)                     //最远距离等于节点个数
        flag = true;
    if(flag)
        printf("YES %d", lastNode);
    else
        printf("NO %d", root);
    return 0;
}

 

4,解题过程

第一搏

DFS+完全二叉数组

#include<bits/stdc++.h>
using namespace std;
struct node{
    int left, right;
}tree[25];
int N, root, lastNode;
int binTree[1000];//数组记录完全二叉树
void dfs(int start, int dep){
    if(start == -1)
        return;

    binTree[dep] = start;
    dfs(tree[start].left, 2 * dep + 1);
    dfs(tree[start].right, 2 * dep + 2);
}
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

    scanf("%d", &N);
    bool notRoot[N], flag = true;
    char c1, c2;
    node n;
    for(int i = 0; i < N; i++){//节点编号从0开始
        cin>>c1>>c2;
        n.left = (c1 == '-' ? -1 : c1-'0');
        n.right = (c2 == '-' ? -1 : c2-'0');
        if(n.left != -1) notRoot[n.left] = true;
        if(n.right != -1) notRoot[n.right] = true;
        tree[i] = n;
    }
    for(int i = 0; i < N; i++)//寻找根节点
        if(!notRoot[i]){
            root = i;
            break;
        }
    fill(binTree, binTree + 1000, -1);
    dfs(root, 0);
    lastNode = binTree[N-1];//最后一个节点
    for(int i = 0; i < N; i++){
        if(binTree[i] == -1)
            flag = false;
    }
    if(flag)
        printf("YES %d", lastNode);
    else
        printf("NO %d", root);
    return 0;
}

第二搏

突然发现,节点编号并不一定是单个字符,于是:

第三搏

???应该没问题了呀

我又把程序来来回回看了无数遍,又去翻阅其他大佬的博客,又辗转回来继续研究,然而还是没问题(虽然我的代码逻辑有点复杂,【看到一位大佬的解法和我类似,但更加简洁】,但理论上说应该完全可行的呀)

几经周折之后,我锁定了一个位置:

(若i不是根节点,则notRoot[i]=true;)

在我最开始的代码里没有将此数组全部初始化为false(因为我以为默认值就是0.。。。所以就没管它),但确实没有别的地方可改了,于是决定搏一搏(接收数据之前先初始化),

于是单车变摩托o(* ̄▽ ̄*)ブ:

#include<bits/stdc++.h>
using namespace std;
struct node{
    int left, right;
}tree[25];
int N, root, lastNode;
int binTree[10000];//数组记录完全二叉树
void dfs(int start, int dep){
    if(start == -1)
        return;

    binTree[dep] = start;
    dfs(tree[start].left, 2 * dep + 1);
    dfs(tree[start].right, 2 * dep + 2);
}
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE

    scanf("%d", &N);
    bool notRoot[N], flag = true;       //若i不是根节点,则notRoot[i]=true
    string s1, s2;
    node n;
    fill(notRoot, notRoot + N, false);  // !!!
    for(int i = 0; i < N; i++){         //节点编号从0开始
        cin>>s1>>s2;
        n.left = (s1 == "-" ? -1 : stoi(s1));
        n.right = (s2 == "-" ? -1 : stoi(s2));
        if(n.left != -1) notRoot[n.left] = true;
        if(n.right != -1) notRoot[n.right] = true;
        tree[i] = n;
    }
    for(int i = 0; i < N; i++)          //寻找根节点
        if(!notRoot[i]){
            root = i;
            break;
        }
    fill(binTree, binTree + 10000, -1);
    dfs(root, 0);
    lastNode = binTree[N-1];//最后一个节点
    for(int i = 0; i < N; i++){
        if(binTree[i] == -1){
            flag = false;
            break;
        }
    }
    if(flag)
        printf("YES %d", lastNode);
    else
        printf("NO %d", root);
    return 0;
}

 

第四搏

欣赏了和我解法类似的大神思路,发现可以进一步简化,比如不需要BinTree数组,只需要DFS时记录最远的位置maxDep即可,若maxDep==N,说明为完全二叉树(具体见思路)。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值