二叉树题目汇总

给出一棵二叉树,返回其节点值的前序遍历。

样例

样例 1:

输入:{1,2,3}
输出:[1,2,3]
解释:
   1
  / \
 2   3
它将被序列化为{1,2,3}
前序遍历

样例 2:

输入:{1,#,2,3}
输出:[1,2,3]
解释:
1
 \
  2
 /
3
它将被序列化为{1,#,2,3}
前序遍历

挑战

你能使用非递归实现么?

 

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Preorder in ArrayList which contains node values.
     */
    vector<int> res;

    vector<int> preorderTraversal(TreeNode * root) {
        // write your code here
        // 递归方式
        // if (root == NULL){
        //     return res;
        // }
        
        // res.push_back(root->val);
        
        // if(root->left){
        //     preorderTraversal(root->left);
            
        // }
        // if(root->right){
        //     preorderTraversal(root->right);
        // }
        
        // return res;
        
        // 非递归方式
        
        if (root == NULL){
            return res;
        }
        
        stack<TreeNode *> node;
        node.push(root);
        
        while(!node.empty()){
            TreeNode * temp = node.top();
            res.push_back(temp->val);
            node.pop();
            
            if(temp->right){
                node.push(temp->right);
            }
            if(temp->left){
                node.push(temp->left);
            }
            
        }
        
        return res;
        
    }
};

  

 

给出一棵二叉树,返回其中序遍历

样例

样例 1:

输入:{1,2,3}
输出:[2,1,3]
解释:
   1
  / \
 2   3
它将被序列化为{1,2,3}
中序遍历

样例 2:

输入:{1,#,2,3}
输出:[1,3,2]
解释:
1
 \
  2
 /
3
它将被序列化为{1,#,2,3}
中序遍历

挑战

你能使用非递归算法来实现么?

 

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Inorder in ArrayList which contains node values.
     */
    vector<int> res;
    vector<int> inorderTraversal(TreeNode * root) {
        // write your code here
        
        //递归方式
        // if(root==NULL){
        //     return res;
        // }
        
        // if(root->left){
        //     inorderTraversal(root->left);
        // }
        
        // res.push_back(root->val);
        
        // if(root->right){
        //     inorderTraversal(root->right);
        // }
        
        // return res;
        
        //非递归方式
        
        if(root==NULL){
            return res;
        }
        
        stack<TreeNode*> node;
        
        
        while(!node.empty()||root!=NULL){
            
            if(root!=NULL){
                //根节点入栈然后不断入栈左子节点,直到为空
                node.push(root);
                root=root->left;
            }else{
                TreeNode * temp= node.top();
                node.pop();
                res.push_back(temp->val);
                //注意这里不是root = root->right ,因为此时的root 本身已经是NULL,所以是不存在任何节点信息的,应该用栈顶元素temp去赋值
                root = temp->right;
            }
            
        }
        
        return res;
        
        
    }
};

  

 

 

给出一棵二叉树,返回其节点值的后序遍历。

样例

样例 1:

输入:{1,2,3}
输出:[2,3,1]
解释: 
   1
  / \
 2   3
它将被序列化为{1,2,3}
后序遍历

样例 2:

输入:{1,#,2,3}
输出:[3,2,1]
解释: 
1
 \
  2
 /
3
它将被序列化为{1,#,2,3}
后序遍历

挑战

你能使用非递归实现么?

 

 
/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */


class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Postorder in ArrayList which contains node values.
     */
     
     
    vector<int> res;
    vector<int> postorderTraversal(TreeNode * root) {
        // write your code here
        // 递归方式
        // if (root==NULL){
        //     return res;
        // }
        
        // if(root->left){
        //     postorderTraversal(root->left);
        // }
        
        
        // if(root->right){
        //     postorderTraversal(root->right);
        // }
        
        // res.push_back(root->val);
        
        // return res;
        
        
        // 非递归方式
        if (root==NULL){
            return res;
        }
               
        stack<TreeNode *> node;
        //当前节点
        TreeNode * cur;
        //前一次访问的结点 
        TreeNode *pre=NULL;
        
        node.push(root);
        
        
        while(!node.empty()){
            cur = node.top();
            //如果当前结点没有孩子结点或者孩子节点都已被访问过 
            if((cur->left==NULL&&cur->right==NULL)||(pre!=NULL&&(pre==cur->left||pre==cur->right)))
            {
                res.push_back(cur->val);
                node.pop();
                pre=cur;
            }
            else{
                if(cur->right){
                    node.push(cur->right);
                }
                if(cur->left){
                    node.push(cur->left);
                }
            }
        }
        
        return res;
        
        
    }
};

  

 

 

 

 

 

 

给出一棵二叉树,返回其节点值的层次遍历(逐层从左往右访问)

样例

样例 1:

输入:{1,2,3}
输出:[[1],[2,3]]
解释:
   1
  / \
 2   3
它将被序列化为{1,2,3}
层次遍历

样例 2:

输入:{1,#,2,3}
输出:[[1],[2],[3]]
解释:
1
 \
  2
 /
3
它将被序列化为{1,#,2,3}
层次遍历

挑战

挑战1:只使用一个队列去实现它

挑战2:用BFS算法来做

 

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: A Tree
     * @return: Level order a list of lists of integer
     */
    vector<vector<int>> levelOrder(TreeNode * root) {
        // write your code here
        
        //最终的res长度的行数其实也是二叉树的深度
        vector<vector<int>> res;
        
        if(root==NULL){
            return res;
        }
        //采用广度优先遍历,用队列来实现
        queue<TreeNode *> q;
        
        // 这里需要结果集合是一个二维vector,所以需要额外定义一个变量记录每一层的节点个数
        int len;
        
        q.push(root);
        
        while(!q.empty()){
            
            len = q.size();
            vector<int> level;
            while(len>0){
                TreeNode *temp = q.front();
                level.push_back(temp->val);
                q.pop();
                len--;
                if(temp->left){
                    q.push(temp->left);
                }
                if(temp->right){
                    q.push(temp->right);
                }
            }
            
            res.push_back(level);
        
        }
        
        return res;
    }
};

  

 

给出一棵二叉树,返回其节点值从底向上的层次序遍历(按从叶节点所在层到根节点所在的层遍历,然后逐层从左往右遍历)

样例

例1:

输入:
{1,2,3}
输出:
[[2,3],[1]]
解释:
    1
   / \
  2   3
它将被序列化为 {1,2,3}
层次遍历

例2:

输入:
{3,9,20,#,#,15,7}
输出:
[[15,7],[9,20],[3]]
解释:
    3
   / \
  9  20
    /  \
   15   7
它将被序列化为 {3,9,20,#,#,15,7}
层次遍历
 
 
输入测试数据 (每行一个参数)如何理解测试数据?

 

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: A tree
     * @return: buttom-up level order a list of lists of integer
     */
    vector<vector<int>> levelOrderBottom(TreeNode * root) {
        // write your code here
        vector<vector<int>> res;
        //这里需要将原始层次遍历的结果添加顺序倒序;
        
        if(root==NULL){
            return res;
        }
        
        queue<TreeNode*> q;
        int len;
        
        q.push(root);
        
        while(!q.empty()){
            vector<int> level;
            len = q.size();
            
            while(len>0){
                TreeNode* temp = q.front();
                level.push_back(temp->val);
                q.pop();
                len--;
                
                if(temp->left){
                    q.push(temp->left);
                }
                
                
                if(temp->right){
                    q.push(temp->right);
                }
            }
            
            // 将原来插入尾部的写法改成插入头部即可
            res.insert(res.begin(),level);
        }
        
        return res;
        
    }
};

  

 

给定一棵二叉搜索树,请找出其中第k大的节点。

 

示例 1:

输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
  2
输出: 4
示例 2:

输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 4

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int kthLargest(TreeNode* root, int k) {
        //存储中序遍历结果,然后输出倒数第k个元素即可

        if(root==NULL || k<= 0){
            return -999;
        }


        vector<int> res;
        inorder(root,res);

        return res[res.size()-k];

 
    }

    // 注意,这里参数进行值传递的方式
    void inorder(TreeNode* root,vector<int>& res){
        if(root==NULL){
            return;
        }
        if(root->left!=NULL){
           inorder(root->left,res);
        }
        res.push_back(root->val);
        if(root->right!=NULL){
           inorder(root->right,res);
        }
    }


};

  

 

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

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

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

 

 

示例 1:

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

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

//  思路: 递归思想,如果两个节点分别在树的左右子树,则返回根节点。
//  如果均在左子树则递归左子树,均在右子树则递归右子树

// 二叉搜素树的性质可以判断节点在左子树还是右子树



class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {

    	if(root==NULL || p==NULL || q==NULL){

    		return NULL;
    	}

    	if(p==root || q == root){
    		return root;
    	}

    	if((p->val>root->val&&q->val<root->val)||(p->val<root->val&&q->val>root->val))
    	{
    		return root;
    	}

    	if(p->val<root->val&&q->val<root->val){
    		return lowestCommonAncestor(root->left,p,q);
    	}

    	if(p->val>root->val&&q->val>root->val){
    		return lowestCommonAncestor(root->right,p,q);
    	}

        return NULL;

    }


};

  

 

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

百度百科中最近公共祖先的定义为:“对于有根树 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。因为根据定义最近公共祖先节点可以为节点本身。

 

思路:

在root的左子树和右子树同时找p和q,若p和q分别分布在root的左右子树,则root为所求
若左子树返回NULL,则说明p和q都在右子树,则进入右子树做1.
若右子树返回NULL,则说明p和q都在左子树,则进入左子树左1.

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        //先找到p或者q就返回
        if(root == NULL || root == p || root == q) return root;
        //在左子树找p或q,假如p和q都在左子树,返回的那个值就是祖先
        TreeNode *left = lowestCommonAncestor(root->left, p, q);
        //在右子树找p或者q,假如p和q都在右子树,返回的那个值就是祖先
        TreeNode *right = lowestCommonAncestor(root->right, p, q);
        if(left == NULL) return right;
        if(right == NULL) return left;
        // p和q一个在左子树一个在右子树
        return root;
    }
};

  

 

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例: 
给定如下二叉树,以及目标和 sum = 22,

5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

 

思路:递归思想
如果根节点值等于目标值返回true
否则,遍历左子树,目标值减去根节点值
同理,遍历右子树,目标值减去根节点值

理解清楚题意,必须是从根节点到叶子节点的路径才可以

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {

    	if(root==NULL){
    		return false;
    	}


    	if(root->val == sum && root->left ==NULL && root->right == NULL){
    		return true;
    	}

    	bool left;
    	left = hasPathSum(root->left,sum-root->val);

    	bool right;
    	right = hasPathSum(root->right,sum-root->val);

    	return left||right;

        
    }
};

  

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

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,

5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:

[
[5,4,11,2],
[5,8,4,5]
]

 回溯思想:

1)结束条件

2)路径、选择列表

3)回溯,撤销选择

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
//思路:可以遍历所有路径,然后将符合条件的路径存下来,采用深度优先遍历

class Solution {
public:
	
	//深度遍历,存储符合条件的路径
    void DFS(TreeNode* root, vector<int>& path, int sum)
    {
        if(root == nullptr)
            return;
        path.push_back(root->val);
        if(root->val == sum && root->left == nullptr && root->right == nullptr)
        // 是叶子节点且从根节点到叶子节点路径总和=sum -> 符合题目的路径
            res.push_back(path);
        // if(root->left)
        DFS(root->left, path, sum - root->val);
        // if(root->right)
        DFS(root->right, path, sum - root->val);
        // 弹出最后一个元素,回溯
        path.pop_back();
    }


    vector<vector<int>> res;
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<int> path;
        DFS(root, path, sum);
        return res;
    }
};

  

给定一个二叉树,检查它是否是镜像对称的。

 

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

 

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

 

方法一:递归

思路和算法

如果一个树的左子树与右子树镜像对称,那么这个树是对称的。

因此,该问题可以转化为:两个树在什么情况下互为镜像?

如果同时满足下面的条件,两个树互为镜像:

1)它们的两个根结点具有相同的值
2)每个树的右子树都与另一个树的左子树镜像对称

 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool check(TreeNode *p, TreeNode *q) {
        if (!p && !q) return true;//若两者均为空
        if (!p || !q) return false;//若其中一个为空,另一个不为空
        return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
    }

    bool isSymmetric(TreeNode* root) {
        return check(root, root);
    }
};

  

「方法一」中我们用递归的方法实现了对称性的判断,那么如何用迭代的方法实现呢?首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。
初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),
然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。

 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

 //递归
// class Solution {
// public:
//     bool check(TreeNode *p, TreeNode *q) {
//         if (!p && !q) return true;
//         if (!p || !q) return false;
//         return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
//     }

//     bool isSymmetric(TreeNode* root) {
//         return check(root, root);
//     }
// };

// 迭代,队列实现
class Solution {
public:
    bool check(TreeNode *u, TreeNode *v) {
        queue <TreeNode*> q;
        q.push(u); q.push(v);
        while (!q.empty()) {
            u = q.front(); q.pop();
            v = q.front(); q.pop();
            if (!u && !v) continue;
            if ((!u || !v) || (u->val != v->val)) return false;

            q.push(u->left); 
            q.push(v->right);

            q.push(u->right); 
            q.push(v->left);
        }
        return true;
    }

    bool isSymmetric(TreeNode* root) {
        return check(root, root);
    }
};

  

 

 

给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

返回 3。和等于 8 的路径有:

1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11

 

递归思想:
递归的基本思想是某个函数直接或者间接地调用自身,这样就把原问题的求
解转换为许多性质相同但是规模更小的子问题。我们只需要关注如何把原问
题划分成符合条件的子问题,而不需要去研究这个子问题是如何被解决的。
递归和枚举的区别在于:枚举是横向地把问题划分,然后依次求解子问题,
而递归是把问题逐级分解,是纵向的拆分。

 

以下会举例说明我对递归的一点理解,如果你不想看下去了,请记住这几个问题怎么回答:
1. 如何给一堆数字排序? 答:分成两半,先排左半边再排右半边,最后合并就行了,至于怎么排左边和右边,请重新阅读这句话。
2. 孙悟空身上有多少根毛? 答:一根毛加剩下的毛。
3. 你今年几岁? 答:去年的岁数加一岁,1999 年我出生。

递归详解:
递归代码最重要的两个特征:结束条件和自我调用。自我调用是在解决子问题,而结束条件定义了最简子问题的答案。

 

int func(你今年几岁) {
// 最简子问题,结束条件
    if (你1999年几岁) 
        return 我0岁; 
    // 自我调用,缩小规模
    return func(你去年几岁) + 1;
}

  

为什么要写递归
首先为了训练逆向思考的能力。递推的思维是正常人的思维,总是看着眼前
的问题思考对策,解决问题是将来时;递归的思维,逼迫我们倒着思考,看
到问题的尽头,把解决问题的过程看做过去时。

递归详解
第二,练习分析问题的结构,当问题可以被分解成相同结构的小问题时,你能敏锐发现这个特点,进而高效解决问题。
第三,跳出细节,从整体上看问题。再说说归并排序,其实可以不用递归来 划分左右区域的,但是代价就是代码极其难以理解,
大概看一下代码(归并 排序在后面讲,这里大致看懂意思就行,体会递归的妙处):

我的一点心得是:明白一个函数的作用并相信它能完成这个任务,千万不要试图跳进细节。
千万不要跳进这个函数里面企图探究更多细节,否则就会陷 入无穷的细节无法自拔,人脑能压几个栈啊。---哈哈哈

// 遍历二叉树
void traverse(TreeNode* root) { 
    if (root == nullptr) return;
    traverse(root->left); 
    traverse(root->right);
}


// 遍历多叉树
void traverse(TreeNode* root) { 
    if (root == nullptr) return;
    for (child : root->children)
        traverse(child);
}

 

 /* 有了以上铺垫,代码如下 */

// PathSum 函数:给他一个节点和一个目标值,他返回以这个节点为根的树中,和为目标值的路径总数。
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int pathSum(TreeNode* root, int sum) {
        if (root == NULL) return 0;
        int pathImLeading = count(root, sum); // 自己为开头的路径数
        int leftPathSum = pathSum(root->left, sum); // 左边路径总数(相信他能算出来)
        int rightPathSum = pathSum(root->right, sum); // 右边路径总数(相信他能算出来)
        return leftPathSum + rightPathSum + pathImLeading;
    }

    //count 函数:给他一个节点和一个目标值,他返回以这个节点为根的树中, 能凑出几个以该节点为路径开头,和为目标值的路径总数。
    int count(TreeNode* node, int sum) {
        if (node == NULL) return 0;
        // 我自己能不能独当一面,作为一条单独的路径呢?
        int isMe = (node->val == sum) ? 1 : 0;
        // 左边的小老弟,你那边能凑几个 sum - node.val 呀?
        int leftBrother = count(node->left, sum - node->val);
        // 右边的小老弟,你那边能凑几个 sum - node.val 呀?
        int rightBrother = count(node->right, sum - node->val); 
        return isMe + leftBrother + rightBrother; // 我这能凑这么多个
    }
};

  

 

 


1325. 删除给定值的叶子节点(C++)

给你一棵以 root 为根的二叉树和一个整数 target ,请你删除所有值为 target 的 叶子节点 。

注意,一旦删除值为 target 的叶子节点,它的父节点就可能变成叶子节点;如果新叶子节点的值恰好也是 target ,那么这个节点也应该被删除。
也就是说,你需要重复此过程直到不能继续删除。


思路:二叉树的题目,最好优先考虑用递归解决,逻辑比较简单
利用树的后序遍历(左右根),由下至上、由左至右的删除值为target的叶子节点

 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* removeLeafNodes(TreeNode* root, int target) 
    {
        if(NULL==root)
        {
            return root;
        }
        root->left=removeLeafNodes(root->left,target);
        root->right=removeLeafNodes(root->right,target);
        if(NULL==root->left && NULL==root->right)
        {
            if(root->val==target)
            {
                return NULL;
            }
        }
        return root;
    }
};

  

 

110. 平衡二叉树

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

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

 

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

 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:

    int high(TreeNode* root){
        if(root==NULL){
            return 0;
        }
        return max(high(root->left),high(root->right))+1;
    }
    bool isBalanced(TreeNode* root) {
        if(root==NULL){
            return true;
        }
        if(root->left==NULL&&root->right==NULL){
            return true;
        }

        return isBalanced(root->left)&&isBalanced(root->right)&&(abs(high(root->left)-high(root->right))<=1);
        
    }
};

  

 

98. 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

 
class Solution {
public:
    void help(vector<int> &vec,TreeNode *root){
        //使用中序遍历,将元素压入容器;
        if(root==NULL) 
            return ; 
        help(vec,root->left); 
        vec.push_back(root->val); 
        help(vec,root->right); 
    } 
    bool isValidBST(TreeNode *root) { 
        if(root==NULL) 
            return true; 
        vector<int> vec; 
        help(vec,root);
     
        int last=vec[0]; 
        vec.erase(vec.begin()); 
        for(auto e:vec){ 
            if(last>=e) 
                return false; 
            last=e;     
        } 
        return true; 
    }
};

  

 

450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

首先找到需要删除的节点;
如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。

示例:

root = [5,3,6,2,4,null,7]
key = 3

5
/ \
3 6
/ \ \
2 4 7

给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。

一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。

5
/ \
4 6
/ \
2 7

另一个正确答案是 [5,2,6,null,4,null,7]。

5
/ \
2 6
\ \
4 7

 

思路:

// 第一种情况:没找到删除的节点,遍历到空节点直接返回了
// 第二种情况:左右孩子都为空(叶子节点),直接删除节点,返回NULL为根节点
// 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
// 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
// 并返回删除节点右孩子为新的根节点。

 

 

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
        if (root->val == key) {
            // 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
            // 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
            if (root->left == nullptr) return root->right; 
            // 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
            else if (root->right == nullptr) return root->left; 
            // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
            // 并返回删除节点右孩子为新的根节点。
            else {  
                TreeNode* cur = root->right; // 找右子树最左面的节点
                while(cur->left != nullptr) { 
                    cur = cur->left;
                }
                cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
                TreeNode* tmp = root;   // 把root节点保存一下,下面来删除
                root = root->right;     // 返回旧root的右孩子作为新root
                delete tmp;             // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
                return root;
            }
        }
        if (root->val > key) root->left = deleteNode(root->left, key);
        if (root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

  

 

701. 二叉搜索树中的插入操作


给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。
保证 ,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。


思路:比删除二叉树节点要简单一些,思路类似:
1)如果节点空,直接创建一个节点,并返回
2)如果待插入的值大于根节点值,则递归调用右子树
3)如果待插入的值小于根节点值,则递归调用左子树
4)如果待插入的值等于根节点值,若左子树为空则直接插入左子树,右子树为空则直接插入右子树,
若左右子树都不为空,则将它插入到右子树,并修改原来指向右子树的指针
5)返回根节点

 

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        TreeNode * node = new TreeNode(val);
        if (root == nullptr){
            return node;
        }

        if(root->val>val){
            root->left = insertIntoBST(root->left,val);
        }
        else if(root->val<val){
            root->right = insertIntoBST(root->right,val);
        }
        else if(root->val==val){
            if(root->left==NULL){
                root->left =node;
            }
            if(root->right==NULL){
                root->right = node;
            }
            if(root->left&&root->right){
                TreeNode* cur =root->right;
                root->right = node;
                node->right = cur;
            }

        }

        return root;

    }
};

  

 

 

 

 

 

 

 

 二叉树相关题目思路分析:

https://blog.csdn.net/luckyxiaoqiang/article/details/7518888 

 

链表相关题目分析:

https://blog.csdn.net/walkinginthewind/article/details/7393134

 

 博主系列博客,可以多关注一下。

posted @ 2020-09-03 22:12  静悟生慧  阅读(400)  评论(0编辑  收藏  举报