代码随想录算法训练营第14天

代码随想录算法训练营第14天 | 226.翻转二叉树,101.对称二叉树,104.二叉树的最大深度,111.二叉树的最小深度

一、刷题部分

1.1 226.翻转二叉树

1.1.1 题目描述

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例 1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:

输入:root = [2,1,3]
输出:[2,3,1]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目范围在 [0, 100]
  • -100 <= Node.val <= 100

1.1.2 初见思路

直接看题解,加速刷题。

1.1.3 正式做题

本题就是按照某种遍历顺序将每个节点的左右孩子交换位置就可以。先序后序以及层序遍历都是可以的,中序遍历会出问题,画个图试一下就知道了。

使用先序遍历递归法,第一步确定函数参数和返回值,为了统一力扣的接口所以返回当前处理的节点,其实直接 void 也是不影响的。

TreeNode* invertTree(TreeNode* root);

然后确定终止条件:

if(!root) return root;

最后确定单层逻辑,使用先序遍历

swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);

之后复习一下之前练习的迭代法,同样使用先序遍历:

TreeNode* invertTree(TreeNode* root) {
    if (!root) return root;
    stack<TreeNode*> st;
    st.push(root);
    while (!st.empty()) {
        TreeNode* cur = st.top();
        st.pop();
        swap(cur->left, cur->right);
        if(cur->right) st.push(cur->right);
        if(cur->left) st.push(cur->left);
    }
    return root;
}

1.1.4 遇到的困难

没有遇到困难。

1.1.5 本题总结

使用合适的遍历顺序将左右孩子交换。


1.2 101.对称二叉树

1.2.1 题目描述

给你一个二叉树的根节点 root , 检查它是否轴对称。

示例 1:

输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

输入:root = [1,2,2,null,3,null,3]
输出:false

提示:

  • 树中节点数目在范围 [1, 1000]
  • -100 <= Node.val <= 100

进阶:你可以运用递归和迭代两种方法解决这个问题吗?

1.2.2 初见思路

以根结点的孩子开始分成左右两个子树,然后就看两个子树的所有孩子是否刚好和另一边返过来,遍历一下就行。

直接看题解,加速刷题。

1.2.3 正式做题

题解和我的思路并不相同,将问题分成了递归的子问题,先判断子树是否是对称的,然后将信息返回给上层节点,从而继续判断是否对称。这显然是使用后序遍历比较合适了。具体来做是用两个指针分别在左右两边进行遍历,然后进行比较。

首先确定递归函数的参数和返回值:

bool compare(TreeNode* left, TreeNode* right);

然后确定终止条件,这题终止条件情况很多,不要漏:

if (left == NULL && right == NULL) return true;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right != NULL) return false;
else if (left->val != right->val) return false;
//最后剩下的情况就是左右指针都有且数值相同,那就不是终止的情况而是需要继续处理
....
return XXX

第三步就是处理单层递归的逻辑:

//先比较外侧孩子
bool outside = compare(left->left, right->right);
if(!outside) return false;//一侧不同立即返回false
//再比较内侧孩子
bool inside = compare(left->right, right->left);
return inside;

1.2.4 遇到的困难

还有迭代法的思路,看了一下录里的博客就过了,没有上手写。

1.2.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:
    bool isSymmetric(TreeNode* root) {
        return compare(root->left, root->right);
    }
    bool compare(TreeNode* left, TreeNode* right) {
        if(left == NULL && right == NULL) return true;
        else if((bool)left ^ (bool)right) return false;
        else if(left->val != right->val) return false;
        //先将几种最基础的退出条件写出来
        bool flag = compare(left->left, right->right);
        if(!flag) return false;
        flag = compare(left->right, right->left);
        return flag;
    }
};

1.3 104.二叉树的最大深度

1.3.1 题目描述

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

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

示例 2:

输入:root = [1,null,2]
输出:2

提示:

  • 树中节点的数量在 [0, 104] 区间内。
  • -100 <= Node.val <= 100

1.3.2 初见思路

可以使用遍历的方式来统计高度,需要修改一些逻辑。

直接看题解,加速刷题。

1.3.3 正式做题

首先注意深度和高度的定义是不一样的,高度是越靠近根结点越大,深度是越靠近叶子节点越大。从 0 还是 从 1 开始这个不一定,看是计算边的条数还是节点的个数。

使用迭代法,第 1 步,确定参数和返回值:

int getDepth(Treenode* node);

第 2 步,确定终止条件:

if (node == 0) return 0;

第 3 步,写单层函数逻辑:

int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
int depth = 1 + max(leftDepth, rightDepth);
return depth;

这其实是一个后序遍历。

1.3.4 遇到的困难

后面的回溯法 以及 迭代法 由于时间关系,一刷的时候就先跳过了。

1.3.5 本题总结

这类题目需要心里清楚使用什么样的遍历方式最好。

class Solution {
public:
    int maxDepth(TreeNode* root) {
        return getHeight(root);
    }
    int getHeight(TreeNode* cur) {
        if(!cur) return 0;
        return max(getHeight(cur->left), getHeight(cur->right)) + 1;
    }
};

1.4 111.二叉树的最小深度

1.4.1 题目描述

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

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

示例 1:

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

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

提示

  • 树中节点数的范围在 [0, 105]
  • -1000 <= Node.val <= 1000

1.4.2 初见思路

能不能套用上一题的逻辑呢,就是将两个子树的最小高度返回上来再 +1。看起来没问题。快速看一下题解来验证一下吧。

1.4.3 正式做题

本题有个小坑,就是如果根结点的一个孩子是空的,另一个孩子不是空的,那么这里是不算最小深度的,因为题目的定义里要求从叶子节点出发。一个图示很好的说明了这一点:

开始递归三部曲:

  1. 确定递归函数的参数和返回值
int getDepth(TreeNode* node);
  1. 确定终止条件
if (!node) return 0;
  1. 确定单层递归逻辑
int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
int result = 1 + min(leftDepth, rightDepth);
return result;

如果到这里就直接提交了,就会遇到上面说的小坑,

需要把单边空白的情况考虑进去。

int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
if (node->left == NULL && node->right != NULL) {
    return 1 + rightDepth;
}
if (node->left != NULL && node->right == NULL) {
    return 1 + leftDepth;
}
int result = 1 + min(leftDepth, rightDepth);
return result;

1.4.4 遇到的困难

前序遍历、迭代法先跳过,二刷再看。

1.4.5 本题总结

class Solution {
public:
    int minDepth(TreeNode* root) {
        return getDepth(root);
    }
    int getDepth(TreeNode* node) {
        if(!node) return 0;
        int leftDepth = getDepth(node->left);
        int rightDepth = getDepth(node->right);
        if (node->left == NULL && node->right != NULL) {
            return 1 + rightDepth;
        }
        if (node->left != NULL && node->right == NULL) {
            return 1 + leftDepth;
        }
        int result = 1 + min(leftDepth, rightDepth);
        return result;
    }
};

二、总结与回顾

相当于对二叉树遍历进行了一些简单的应用,已经有点摸到门道的感觉了。

posted @ 2025-02-14 00:06  xc0208  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示