【C/C++】513. 找树左下角的值

174 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第34天,点击查看活动详情


题目链接:513. 找树左下角的值

题目描述

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

提示:

  • 二叉树的节点个数的范围是 [1,104][1, 10^4]
  • 231 Node.val231 1-2^{31} \leqslant Node.val \leqslant 2^{31} - 1

示例 1:

tree1.jpg

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

示例 2:

tree2.jpg

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7

整理题意

给定一棵二叉树的根节点,找到这棵二叉树 最底层 最左边 节点的值。

题目提示该二叉树至少有一个节点。

解题思路分析

涉及到图和树的题目,一般都要遍历图或树。

  • 由于题目要找最底层的元素,所以可以使用 BFS 广度优先搜索 进行层序遍历。
  • 考虑到最左边的元素,我们还可以使用 DFS 深度优先搜索 进行遍历查找最左边的元素。

具体实现

BFS 广度优先搜索

  1. 从根节点开始层序遍历。
  2. 每次取出一层所有元素进行遍历,记录每层第一个元素即为最左边的元素,直至最后一层最左边的元素。

需要注意每次放入队列的顺序为先放左节点,再放右节点,这样可以保证每层第一个元素就为队列第一个元素。

DFS 深度优先搜索

  1. 从根节点开始遍历,遍历时需要一个变量来记录当前层数。
  2. 每层第一个遍历到的元素就为最左边的元素。
  3. 记录当前遍历的最大层数,当最大层数增加时,记录当前元素,因为此时为最大层数的第一个元素,也就是最左边的元素。

需要注意的是每次先遍历左子树再遍历右子树,这样可以保证当最大层数发生变化时,所遍历到的元素为当前层最左边的元素。

复杂度分析

  • 时间复杂度:O(n)O(n),其中 n 是二叉树的节点数目。需要遍历 n 个节点。
  • 空间复杂度:O(n)O(n),如果二叉树是满完全二叉树,那么 BFS 广度优先搜索队列 que 最多保存 n2\big \lceil \dfrac{n}{2} \big \rceil 个节点。DFS 深度优先搜索递归栈需要占用 O(n)O(n) 的空间。

代码实现

BFS 广度优先搜索

/**
 * 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 findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        while(que.size()) que.pop();
        que.push(root);
        int ans = root->val;
        //层序遍历
        while(que.size()){
            int n = que.size();
            //flag 记录每层是否已经记录第一个元素
            int flag = 1;
            for(int i = 0; i < n; i++){
                TreeNode* now = que.front();
                que.pop();
                //记录每层第一个元素
                if(flag){
                    flag = 0;
                    ans = now->val;
                }
                //压入下一层元素
                if(now->left != nullptr) que.push(now->left);
                if(now->right != nullptr) que.push(now->right);
            }
        }
        return ans;
    }
};

DFS 深度优先搜索

/**
 * 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:
    //ans记录最底层最左边的元素,m记录当前遍历的最大层数
    int ans, m;
    //遍历二叉树,同时维护当前树的深度
    void dfs(TreeNode* now, int deep){
        //当最大层数发生变化时记录最左边的元素
        if(deep > m){
            m = deep;
            ans = now->val;
        }
        //遍历左右子树,注意先遍历左子树
        if(now->left != nullptr) dfs(now->left, deep + 1);
        if(now->right != nullptr) dfs(now->right, deep + 1);
    }
public:
    int findBottomLeftValue(TreeNode* root) {
        //初始化最大层数和最左边的节点值
        m = 0;
        ans = root->val;
        dfs(root, 0);
        return ans;
    }
};

总结

  • 涉及图和树的题目往往需要遍历图和树,涉及遍历问题,通常需要考虑广度优先搜索和深度优先搜索。
  • 需要注意遍历顺序,由于该题求的时最左边的元素节点,所以先遍历左子树再遍历右子树。
  • 测试结果:

513.png

513DFS.png

结束语

人生犹如走山路,可能会历经高峰,也会落入低谷。想要冲出低谷,就要学会调整心态、沉淀自己。好的心态,是面对风雨,迎难而上;是身在低谷,不轻言放弃。拥有好的心态,我们才能在遭遇挫折时笑着面对。