1159 Structure of a Binary Tree + 根据前序和中序构建二叉树+ 层序遍历模板复习

Posted 江柏英的技术博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1159 Structure of a Binary Tree + 根据前序和中序构建二叉树+ 层序遍历模板复习相关的知识,希望对你有一定的参考价值。

题目链接https://pintia.cn/problem-sets/994805342720868352/exam/problems/1478635126488367104

唉,今天的bug出在了下面这条语句。

if (tree[root_key].left * tree[root_key].right < 0) full_tree = false;

我写成了

full_tree = !(tree[root_key].left * tree[root_key].right < 0); // 这就会导致full_tree即便变成了false也有可能变回true。导致错判。

根据前序和中序构建二叉树

参考的柳神代码,灵活的点就在于,用下标表示数组区间,嗯,相比直接传数组的引用,轻了不少。

int build(int R, int start, int end, int fa)  // 1. post数组的最右边的位置;2. start, end : in数组的起始位置;3. 对于这题来说还需要记录父节点fa。
    if (start > end) return -1;
    int root_key = post[R], pos = start;
    while (in[pos] != root_key && pos < end) pos++;
    tree[root_key].level = tree[fa].level + 1;
    tree[root_key].fa = fa;
    tree[root_key].left = build(R - 1 - (end - pos), start, pos - 1, root_key); // 记住post的最后一个元素的下标一定要用 R 来相对计算,而不是只用 pos,不然在递归的过程中,即便前几层看不出什么,往后一定会发生错位。
    tree[root_key].right = build(R - 1, pos + 1, end, root_key);  // 下标的选择是经常容易出bug的,一定要想清楚
    if (tree[root_key].left * tree[root_key].right < 0) full_tree = false;
    return root_key;

题解代码:

#include<iostream>
#include<vector>
#include<string>
#include<queue>
using namespace std;
int n, m;
struct Node 
    Node() 
        fa = left = right = -1;
    
    int level, fa, left, right;
 tree[1005];
bool full_tree = true;
int in[35], post[35], num1, num2;
int build(int R, int start, int end, int fa)  // 1. post数组的最右边的位置;2. start, end : in数组的起始位置;3. 对于这题来说还需要记录父节点fa。
    if (start > end) return -1;
    int root_key = post[R], pos = start;
    while (in[pos] != root_key && pos < end) pos++;
    tree[root_key].level = tree[fa].level + 1;
    tree[root_key].fa = fa;
    tree[root_key].left = build(R - 1 - (end - pos), start, pos - 1, root_key); // 记住post的最后一个元素的下标一定要用 R 来相对计算,而不是只用 pos,不然在递归的过程中,即便前几层看不出什么,往后一定会发生错位。
    tree[root_key].right = build(R - 1, pos + 1, end, root_key);  // 下标的选择是经常容易出bug的,一定要想清楚
    if (tree[root_key].left * tree[root_key].right < 0) full_tree = false;
    return root_key;

bool siblings(int a, int b) 
    return tree[a].fa == tree[b].fa;

bool same_level(int a, int b) 
    return tree[a].level == tree[b].level;

bool parent(int a, int b) 
    return tree[b].fa == a;

bool left_child(int a, int b) 
    return tree[b].left == a;

bool right_child(int a, int b) 
    return tree[b].right == a;

int main() 
    cin >> n;
    for (int i = 0; i < n; i++) cin >> post[i];
    for (int i = 0; i < n; i++) cin >> in[i];
    int root = post[n - 1];
    build(n - 1, 0, n - 1, 0);
    cin >> m;
    while (m--) 
        string str;
        cin >> str;
        if (str[0] == \'I\')  
            getline(cin, str);
            cout << (full_tree ? "Yes" : "No") << endl;
         else 
            num1 = stoi(str);
            cin >> str;
            if (str[0] == \'a\') 
                cin >> num2 >> str >> str;
                if (str[0] == \'s\') 
                    cout << (siblings(num1, num2) ? "Yes" : "No") << endl;
                 else 
                    getline(cin, str);
                    cout << (same_level(num1, num2) ? "Yes" : "No") << endl;
                
             else 
                cin >> str >> str;
                switch(str[1]) 
                    case \'o\' : 
                        cout << (root == num1 ? "Yes" : "No") << endl;
                     break;
                    case \'a\' : 
                        cin >> str >> num2;
                        cout << (parent(num1, num2) ? "Yes" : "No") << endl;
                     break;
                    case \'e\' : 
                        cin >> str >> str >> num2;
                        cout << (left_child(num1, num2) ? "Yes" : "No") << endl;
                     break;
                    case \'i\' : 
                        cin >> str >> str >> num2;
                        cout << (right_child(num1, num2) ? "Yes" : "No") << endl;
                     break;
                               
            
        
    
    return 0;

刚做的时候以为要用层序遍历,顺便复习一下吧。

层序遍历模板代码:

vector<vector<int>> level_order(Node *root) 
    vector<vector<int>> res;
    queue<Node *> q;
    if (root) q.push(root);
    while (q.size()) 
        int size = q.size();
        vector<int> v;
        for (int i = 0; i < size; i++) 
            Node *node = q.front();
            q.pop();
            // 上一排的元素依次出队
            v.push_back(node->val);
            // 下一排的节点全部入队
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        
        // 存入一排
        res.push_back(v);
    
    return res;

LeetCode 236.lowest-common-ancestor-of-a-binary-tree

题意

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

示例 1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

示例 2:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。

说明:

所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

从根节点往下遍历,如果当前节点==p或者q,那么直接返回(从上往下找的第一个符合的点必是两点的父亲)。如果当前节点的左子树里有符合条件的点,并且当前节点的右子树也有符合条件的点,那么返回当前节点。如果两个节点的lca出现在左子树或者右子树的一个,那么返回在那个子树找到的结果即可。
时间复杂度O(n),空间复杂度O(n)。
递归很简单。
非递归使用一个HashMap存储每个节点和父亲节点的映射,通过找到p和q的父亲节点,再把p到根节点的路径上的点加入到Set中,最后让q往上爬,找q和p最早相同的节点。

代码

递归:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null||root==p||root==q){
            return root;
        }
        TreeNode l=lowestCommonAncestor(root.left,p,q);
        TreeNode r=lowestCommonAncestor(root.right,p,q);
        if(l!=null&&r!=null){
            return root;
        }
        if(l==null) return r;
        return l;
    }
}

非递归:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        Map<TreeNode,TreeNode> fa=new HashMap<>();
        fa.put(root,null);
        Stack<TreeNode> st=new Stack<>();
        st.add(root);
        while(!fa.containsKey(p)||!fa.containsKey(q)){
            TreeNode cur=st.pop();
            if(cur.left!=null){
                st.add(cur.left);
                fa.put(cur.left,cur);
            }
            if(cur.right!=null){
                st.add(cur.right);
                fa.put(cur.right,cur);
            }
        }
        Set<TreeNode> set=new HashSet<>();
        while(p!=null){
            set.add(p);
            p=fa.get(p);
        }
        while(!set.contains(q)){
            q=fa.get(q);
        }
        return q;
    }
}

以上是关于1159 Structure of a Binary Tree + 根据前序和中序构建二叉树+ 层序遍历模板复习的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 236.lowest-common-ancestor-of-a-binary-tree

Lecture3 Structure of Academic Writing

[Paper] Structure Of The Paper

Structure of a Task

Structure Of Management Information - SNMP Tutorial

Structure And Representation Of MIB Object Names - SNMP Tutorial