Leetcode 二叉树

Pre

  • tree(n个节点的有限集, 且节点满足如下关系)
    • 有且仅有一个节点没有父节点,根(root)
    • 除根外,所有节点有且仅有一个父节点
    • 树中每个节点都构成一个以它为根的子树
  • 二叉树
    • 每个节点最多有两个子树,有左右之分, 左子树和右子树, 次序不可颠倒

深度遍历DFS(Depth_First_Search)

struct TreeNode{
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL{}
};

void preorder_print(TreeNode *node, int layer){

}
int main(){
    TreeNode a(1);
    TreeNode a(2);
    TreeNode a(3);
    TreeNode a(4);
    TreeNode a(5);
    TreeNode a(6);

    a.left=&b;
    a.right=&c;
    b.left=&d;
    b.right=&e;
    c.right=&f;
    preorder_print(&a, 0);


    return 0;
}

二叉树广度遍历BFS(Breadth_First_Search)

伪代码

设置队列Q
将根节点push进Q   Q.push(A)
while(Q不空){
  取出队列头部节点Node Q.pop()
  对Node进行访问 A
  将Node左孩子右孩子push进队列Q Q.push(b), Q.push(c)
}

110. 平衡二叉树(Easy)

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例 1:
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:true

示例 2:
在这里插入图片描述

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
示例 3:
输入:root = []
输出:true

提示:

树中的节点数在范围 [0, 5000] 内
-104 <= Node.val <= 104

class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(!root) return true;
        if(abs(height(root->left)-height(root->right))<=1 &&isBalanced(root->left) &&isBalanced(root->right)){
            return true;
        }else{
            return false;
        }
    }
private:
    int height(TreeNode* node){
        if(!node) return 0;
        return max(height(node->left), height(node->right))+1;
    }
};

113. 路径总和II(Medium)

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例 2:
输入:root = [1,2,3], targetSum = 5
输出:[]
示例 3:
输入:root = [1,2], targetSum = 0
输出:[]

提示:

树中节点总数在范围 [0, 5000] 内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

class Solution {
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<int> item;
        vector<vector<int>> result;
        find_path(root, targetSum, 0, item, result);
        return result;
    }

private:
//一般不用全局变量, 除非遇到多线程开发共同访问全局变量时
    void find_path(TreeNode* root, int target, int sum, vector<int>& item, vector<vector<int>>& result){
        
        /**
         * 错误原因: 叶节点分别访问不存在的左节点和右节点
         * 所以答案会添加两遍
         * 必须在访问叶子节点的时候才可以添加答案
        */
        // if(root==NULL){
        //     if(target==NULL){
        //         result.push_back(item);
        //     }
        //     return;
        // }
        if(root==NULL){
            return;
        }
        sum+=root->val;
        item.push_back(root->val);
        if(sum==target&&!root->left&&!root->right){//判断是叶节点: if(!root->left&&!root->right)
            result.push_back(item);
        }
        //一开始到达这个节点的时候, 做什么事情
        find_path(root->left, target, sum, item, result);
        find_path(root->right, target, sum, item, result);
        // 当回退到这个节点的时候, 做什么事情
        sum-=root->val;
        item.pop_back();
    }
};

114. 二叉树展开为链表(Medium)

给你二叉树的根结点 root ,请你将它展开为一个单链表:

展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1:
在这里插入图片描述
输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [0]
输出:[0]

提示:

树中结点数在范围 [0, 2000] 内
-100 <= Node.val <= 100

方法1:

class Solution {
public:
    void flatten(TreeNode* root) {
        vector<TreeNode*> nodes;
        preorder(root, nodes);
        for(int i=0;i<nodes.size()-1;i++){
            nodes[i]->right=nodes[i+1];
            nodes[i]->left=NULL;
        }
    }
private:
    void preorder(TreeNode* root, vector<TreeNode*>& nodes){
        if(!root) return;
        nodes.push_back(root);
        preorder(root->left, nodes);
        preorder(root->right, nodes);
    }
};

方法2: (In-Place)

class Solution {
public:
    void flatten(TreeNode* root) {
        TreeNode* last=NULL;
        preorder(root, last);
    }
/**
 * 递归
 *  前序: 进入递归之前做什么
 *  中序: 完成第一次递归之后第二次递归之前做什么
 *  后序: 完成二次递归之后做什么
*/
private:
    void preorder(TreeNode* node, TreeNode*&last) {//传出必要信息不使用返回值, 而是用参数的方式保存信息
                                                   // 而且传引用才可以传出信息, 所以last是引用
        if(!node) return;
        if(!node->left&&node->right){
            last=node;
            return;
        }
        TreeNode* left=node->left;
        TreeNode* right=node->right;
        TreeNode* left_last=NULL;
        TreeNode* right_last=NULL;

        if(left){
            preorder(node->left, left_last);
            node->left=NULL;
            node->right=left;
            last=left_last; // 右子树可能为空, 这样传出的last就是左子树的last
        }
        if(right){
            preorder(right, right_last);
            if(left_last){ //左子树不为空
                left_last->right=right;
            }
            last=right_last;
        }
    }
}; 

199. 二叉树的右视图(Medium)

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:
1 <—
/
2 3 <—
\
5 4 <—

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        queue<pair<TreeNode*, int>> Q;
        vector<int> view;
        if(root) Q.push(std::make_pair(root, 0));
        while(!Q.empty()){
            TreeNode* node=Q.front().first;
            int layer=Q.front().second;
            Q.pop();
            if(layer!=view.size()-1){
                view.push_back(node->val);
            }else{
                view[layer]=node->val;
            }
            
            if(node->left) Q.push(make_pair(node->left, layer+1));
            if(node->right) Q.push(make_pair(node->right, layer+1));
        }
        return view;


    }
};

226 翻转二叉树(Easy)

翻转一棵二叉树。

示例:

输入:
4
/
2 7
/ \ /
1 3 6 9
输出:
4
/
7 2
/ \ /
9 6 3 1

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(!root) return NULL;
        TreeNode* tmp=root->left;
        root->left=root->right;
        root->right=tmp;
        
        invertTree(root->left);
        invertTree(root->right);
        return root;

    }
};

236.

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

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

示例 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 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1

提示:

树中节点数目在范围 [2, 105] 内。
-109 <= Node.val <= 109
所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        vector<TreeNode*> path1, path2;
        vector<TreeNode*> path;
        TreeNode* result;
        find_path(root, p, path, path1, false);
        find_path(root, q, path, path2, false);
        int i=0;
        while(i<path1.size()&&i<path2.size()){
            if(path1[i]==path2[i]){
                result=path1[i];
            }
            i++;
        }

        return result;
    }

private:
    void find_path(TreeNode* root, TreeNode *target, vector<TreeNode*>& path, vector<TreeNode*>& result, bool finish){
        if(!root || finish){
            return;
        }
        path.push_back(root);
        if(root==target){
            finish=true;
            result=path;
        }
        find_path(root->left, target, path, result, finish);
        find_path(root->right, target, path, result, finish);
        path.pop_back();


    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值