【面试经典 150 | 二叉树】路径总和

写在前面

本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……

专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:

  • Tag:介绍本题牵涉到的知识点、数据结构;
  • 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
  • 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
  • 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
  • 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。

Tag

【二叉树】【递归】【广度优先搜索】


题目来源

112. 路径总和


解题思路

方法一:递归

递归的方法最容易想到,因为要找是否有从根节点到叶子节点的路径和等于给定值 sum 的情况,排除掉特殊情况(递归出口),只需要判断根节点的左子树或者右子树中有没有从根节点到叶子节点路径和等于 s u m − r o o t − > v a l sum - root->val sumroot>val 的情况,这是一个典型的将大问题缩小为同类的子问题。

子问题

分别判断左子树和右子树中是否有路径和等于 s u m − r o o t − > v a l sum - root->val sumroot>val 的情况。

递归出口

如果根节点 r o o t root root 为空节点,直接返回 f a l s e false false
如果这棵二叉树中仅有一个节点,也就是根节点,就需要判断是否 r o o t − > v a l = = s u m root->val == sum root>val==sum

代码

/**
 * 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 hasPathSum(TreeNode* root, int targetSum) {
		if (root == nullptr)
			return false;

		if (root->left == nullptr && root->right == nullptr)
			return root->val == targetSum;

		return (hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, 
        targetSum - root->val));
	}
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n) n n n 是二叉树中节点数。每节点至多访问一次。

空间复杂度: O ( n ) O(n) O(n),最坏情况下二叉树退化成一条链。

方法二:广度优先搜索

在二叉树中使用的广度优先算法通常都是和二叉树的 “层序遍历” 有关。通常需要维护一个队列 q u e _ n o d e que\_node que_node,用来存放二叉树按层并且从左到右的顺序遍历的节点,在这道题目中,我们还需要再维护一个队列 q u e _ v a l que\_val que_val 用来存放从根节点到当前遍历节点的路径和。

具体地,首先将根节点和 int 型数据分别为入队 q u e _ n o d e que\_node que_node q u e _ v a l que\_val que_val;接着执行循环操作即对这个两个队列执行出队操作,如果当前出队的节点还有子节点,那么将子节点入队 q u e _ n o d e que\_node que_node 并将从根节点到该子节点的路径和存入 q u e _ v a l que\_val que_val 队列。

退出循环的条件是当前出队的节点没有子节点并且出队的值等于目标值,那么直接返回 t r u e true true,或者是存储节点的队列为空。

官方题解 中的【广度优先搜索】的动图更加利于理解。

代码

/**
 * 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 hasPathSum(TreeNode* root, int targetSum) {
        if (!root) {
            return false;
        }
        queue<TreeNode*> que_node;
        queue<int> que_val;
        que_node.push(root);
        que_val.push(root->val);
        while (!que_node.empty()) {
            TreeNode* cur = que_node.front(); que_node.pop();
            int tmpVal = que_val.front(); que_val.pop();
            if (!cur->left && !cur->right) {
                if (tmpVal == targetSum) {
                    return true;
                }
                continue;
            }
            if (cur->left) {
                que_node.push(cur->left);
                que_val.push(cur->left->val + tmpVal);
            }
            if (cur->right) {
                que_node.push(cur->right);
                que_val.push(cur->right->val + tmpVal);
            }
        }
        return false;
    }
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n) n n n 是二叉树中节点数。每节点至多访问一次。

空间复杂度: O ( n ) O(n) O(n)。空间复杂度主要取决于队列的开销,队列中的元素个数不会超过树的节点数。


写在最后

如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。

最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。

  • 18
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wang_nn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值