【PAT甲级题解记录】1110 Complete Binary Tree(25 分)

【PAT甲级题解记录】1110 Complete Binary Tree(25 分)

前言

Problem:1110 Complete Binary Tree (25 分)

Tags:完全二叉树 二叉树的层序遍历 BFS DFS

Difficulty:剧情模式 想流点汗 想流点血 死而无憾

Address:1110 Complete Binary Tree (25 分)

问题描述

给定一棵树,其中有结点 0 to N-1 ,判定是否为完全二叉树。

  • 若是完全二叉树,则需要输出最后一个结点。
  • 若不是,则需要输出这棵树的根结点。

PS:这里给出完全二叉树的定义

一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

解题思路

  • 检查二叉树是否为完全二叉树,其实就是考察二叉树的遍历。结合四种基本遍历方式(pre、in、post、level)各自的特点来选取适合的方法,但说到底就是搜索。

    • 方法一:在层序遍历过程中,有两种情况可供判断是不是完全二叉树:

      • 遇到“无左孩子,有右孩子”的情况,有这种情况可以直接认定为非完全二叉树。
      • 遇到”无孩子“的情况,则接下来的节点都不能有孩子,否则是非完全二叉树。
    • 方法二:可以看出方法一的判断有一点麻烦。由于完全二叉树他的编号与满二叉树一一对应,所以可以直接DFS搜索,然后看每一个结点位置是否都小于N就好了,因为一旦有结点位置不小于N,就与满二叉树无法对应了。(但是这种方法就得在搜索时动态维护当前的结点位置)

  • 这道题在初始化树时,我们并不能直接知道根结点是哪个,需要作额外判断,即没有父结点的就是root。

参考代码

  1. 层序遍历动态判断

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int N;
    vector<pair<int, int>> tree;
    vector<int> have_parent;
    int root;
    
    void init() {
        cin >> N;
        tree.resize(N);
        have_parent.resize(N, 0);
        for (int i = 0; i < N; ++i) {
            string l, r;
            cin >> l >> r;
            if (l == "-") {
                tree[i].first = -1;
            } else {
                tree[i].first = stoi(l);
                have_parent[stoi(l)] = 1;
            }
            if (r == "-") {
                tree[i].second = -1;
            } else {
                tree[i].second = stoi(r);
                have_parent[stoi(r)] = 1;
            }
        }
        for (int i = 0; i < N; ++i) {
            if (have_parent[i] == 0) {
                root = i;
                return;
            }
        }
    }
    
    int main() {
        init();
        queue<int> q;
        q.push(root);
        int last_node = -1;
        bool flag = false;
        while (!q.empty()) {
            int ft = q.front();
            last_node = ft;  // update last_node
            q.pop();
            // check
            if (tree[ft].first == -1 && tree[ft].second != -1) {
                cout << "NO " << root << endl;
                return 0;
            }
            if (flag && (tree[ft].first != -1 || tree[ft].second != -1)) {
                cout << "NO " << root << endl;
                return 0;
            }
            // update flag
            if (tree[ft].first == -1 && tree[ft].second == -1) {
                flag = true;
            }
            // push queue
            if (tree[ft].first != -1) {
                q.push(tree[ft].first);
            }
            if (tree[ft].second != -1) {
                q.push(tree[ft].second);
            }
        }
        cout << "YES " << last_node << endl;
        return 0;
    }
    
  2. DFS直接找最大位置

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int N;
    vector<pair<int, int>> tree;
    vector<int> have_parent;
    int root_node, last_node, max_pos;
    
    void init() {
        cin >> N;
        tree.resize(N);
        have_parent.resize(N, 0);
        for (int i = 0; i < N; ++i) {
            string l, r;
            cin >> l >> r;
            if (l == "-") {
                tree[i].first = -1;
            } else {
                tree[i].first = stoi(l);
                have_parent[stoi(l)] = 1;
            }
            if (r == "-") {
                tree[i].second = -1;
            } else {
                tree[i].second = stoi(r);
                have_parent[stoi(r)] = 1;
            }
        }
        for (int i = 0; i < N; ++i) {
            if (have_parent[i] == 0) {
                root_node = i;
                return;
            }
        }
    }
    
    /**
     *
     * @param root 当前结点编号
     * @param pos  当前搜索位置
     * @return DFS的最大搜索位置
     */
    void dfs(int root, int pos) {
        if (pos > max_pos) {
            max_pos = pos;
            last_node = root;
        }
        if (tree[root].first != -1) {
            dfs(tree[root].first, pos * 2 + 1);
        }
        if (tree[root].second != -1) {
            dfs(tree[root].second, pos * 2 + 2);
        }
    }
    
    int main() {
        init();
        dfs(root_node, 0);
        if (max_pos < N) {
            cout << "YES " << last_node << endl;
        } else {
            cout << "NO " << root_node << endl;
        }
        return 0;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值