代码随想录刷题记录(13)| 二叉树(110.平衡二叉树,257. 二叉树的所有路径,404.左叶子之和,222.完全二叉树的节点个数)

目录

(十)平衡二叉树

1. 题目描述

2. 思路

3. 解题过程

(十一)二叉树的所有路径

1. 题目描述

2. 思路

3. 解题过程

(十二)左叶子之和

1. 题目描述

2. 思路

3. 解题过程

(1) 从二叉树的所有路径改一下

(2)代码随想录的递归

(十三)完全二叉树的节点个数

1. 题目描述

2. 思路

3. 解题过程

(1)改一下前序遍历的迭代写法 

(2)利用完全二叉树的性质


(十)平衡二叉树

110. 平衡二叉树 - 力扣(LeetCode)

1. 题目描述

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

  

2. 思路

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。
  1. 明确递归函数的参数和返回值:参数:当前传入节点。 返回值:以当前传入节点为根节点的树的高度。如果已经不是二叉平衡树了,可以返回 -1 来标记已经不符合平衡树的规则了。
  2. 明确终止条件:递归的过程中遇到空节点了为终止,返回 0,表示当前节点为根节点的树高度为 0。
  3. 明确单层递归的逻辑:分别求出其左右子树的高度,然后如果差值小于等于 1,则返回当前二叉树的高度,否则返回 -1,表示已经不是二叉平衡树了。

3. 解题过程

难易程度:简单

标签:树、深度优先搜索、二叉树

/**
 * 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 {
private:
    int height(TreeNode* root) {
        if(!root)   return 0;
        int left = height(root->left);
        if(left == -1)  return -1;
        int right = height(root->right);
        if(right == -1) return -1;

        if(abs(left - right) > 1)   return -1;
        return max(left, right) + 1;
    }

public:
    bool isBalanced(TreeNode* root) {
        return height(root) != -1;
    }
};

(十一)二叉树的所有路径

257. 二叉树的所有路径 - 力扣(LeetCode)

1. 题目描述

        给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

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

2. 思路

  1. 递归函数参数以及返回值:要传入根节点,记录每一条路径的 path,和存放结果集的 result,这里递归不需要返回值。
  2. 确定递归终止条件:找到叶子节点,使用 vector 结构 path 来记录路径,把 vector 结构的 path 转为 string 格式,再把这个string 放进 result 里。(使用vector方便来做回溯)
  3. 确定单层递归逻辑:因为是前序遍历,需要先处理中间节点,中间节点就是我们要记录路径上的节点,先放进 path 中。在这里递归的时候,如果为空就不进行下一层递归了。【回溯和递归是一一对应的,有一个递归,就要有一个回溯】

3. 解题过程

难易程度:简单

标签:树、深度优先搜索、字符串、回溯、二叉树

class Solution {
private:
    void traversal(TreeNode* root, vector<string>& result, vector<int>& path) {
        path.push_back(root->val);  // 根
        // 遇到叶子节点
        if(!root->left && !root->right) {
            string sPath;
            // 将path里记录的路径转为string格式
            sPath += to_string(path[0]);
            for(int i = 1; i < path.size(); i++) {
                sPath += "->";
                sPath += to_string(path[i]);
            }
            result.push_back(sPath);    // 存进结果里
        }
        if(root->left) {    // 左
            traversal(root->left, result, path);
            path.pop_back();
        }
        if(root->right) {   // 右
            traversal(root->right, result, path);
            path.pop_back();
        }
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        vector<int> path;
        if(!root)   return result;
        traversal(root, result, path);
        return result;
    }
};

(十二)左叶子之和

404. 左叶子之和 - 力扣(LeetCode)

1. 题目描述

        给定二叉树的根节点 root ,返回所有左叶子之和。

2. 思路

        判断当前节点是不是左叶子必须要通过节点的父节点来判断其左孩子是不是左叶子。如果该节点的左节点不为空,该节点的左节点的左节点为空,该节点的左节点的右节点为空,则找到了一个左叶子。

3. 解题过程

难易程度:简单

标签:树、深度优先搜索、广度优先搜索、二叉树

(1) 从二叉树的所有路径改一下
class Solution {
private:
    void traversal(TreeNode* root, int& result, vector<int>& path) {
        path.push_back(root->val);
        if(root->left && !root->left->left && !root->left->right) {
            result += root->left->val;
        }
        if(root->left) {
            traversal(root->left, result, path);
            path.pop_back();
        }
        if(root->right) {
            traversal(root->right, result, path);
            path.pop_back();
        }
    }

public:
    int sumOfLeftLeaves(TreeNode* root) {
        int result = 0;
        vector<int> path;
        traversal(root, result, path);
        return result;
    }
};

(2)代码随想录的递归
  1. 确定递归函数的参数和返回值:判断一个树的左叶子节点之和,要传入树的根节点,递归函数的返回值为数值之和。
  2. 确定终止条件:如果遍历到空节点,那么左叶子值一定是0。
  3. 确定单层递归的逻辑:当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和右子树左叶子之和,相加便是整个树的左叶子之和。
class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;

        int leftValue = sumOfLeftLeaves(root->left);    // 左
        if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
            leftValue = root->left->val;
        }
        int rightValue = sumOfLeftLeaves(root->right);  // 右

        int sum = leftValue + rightValue;               // 中
        return sum;
    }
};

(十三)完全二叉树的节点个数

222. 完全二叉树的节点个数 - 力扣(LeetCode)

1. 题目描述

        给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

2. 思路

        完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。

        对于情况一,可以直接用 2^树深度 - 1 来计算,这里根节点深度为1。

        对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。

3. 解题过程

难易程度:简单

标签:位运算、树、二分查找、二叉树

(1)改一下前序遍历的迭代写法 
class Solution {
public:
    int countNodes(TreeNode* root) {
        int result = 0;
        stack<TreeNode*> preStack;
        if(root)    preStack.push(root);
        while(!preStack.empty()) {
            TreeNode* node = preStack.top();
            preStack.pop();
            result++;
            if(node->right) preStack.push(node->right);
            if(node->left)  preStack.push(node->left);
        }
        return result;
    }
};

(2)利用完全二叉树的性质
class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root)   return 0;
        TreeNode* leftTree = root->left;
        TreeNode* rightTree = root->right;
        int leftDepth = 0, rightDepth = 0;
        while(leftTree) {
            leftTree = leftTree->left;
            leftDepth++;
        }
        while(rightTree) {
            rightTree = rightTree->right;
            rightDepth++;
        }
        // 满二叉树
        if(leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; 
        }
        // 后序
        int leftTreeNum = countNodes(root->left);       // 左
        int rightTreeNum = countNodes(root->right);     // 右
        int result = leftTreeNum + rightTreeNum + 1;    // 中
        return result;
    }
};
  • 17
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值