news 2026/7/4 4:02:06

算法(二叉树)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法(二叉树)

引言

112. 路径总和 - 力扣(LeetCode)

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

617. 合并二叉树 - 力扣(LeetCode)

98. 验证二叉搜索树 - 力扣(LeetCode)

501. 二叉搜索树中的众数 - 力扣(LeetCode)

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

第一题

对于理解这一题,我们主要的重点有两个,一个是传递的参数,我们这里传递的参数是count,其作用主要是记录到每一个结点还需要的和。第二个是返回值,我们可能有的时候是void,有的时候又有返回值,这其实取决于我们需不需要对于处理递归的返回值,如果我们仅仅是计算高度,其实用一个全局变量就可以了,但是这一题我们需要判断路径,当一个结点返回true的时候,说明已经找到了路径,那么就可以把true向上传递返回。而传递这个返回值我们就必须要接受这个返回值,这里用的是if(),如果返回的是int,那么我们就需要用int来接受。

其他的思路就比较的简单,就是在回溯的前面查看一下返回值是不是true,如果是的,就没必要回溯然后往其他的地方去遍历,直接返回。当然,如果我们提供的三个返回true的地方都没有返回true,说明这个结点就是false,那么我们在最后就是return false

/** * 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 traversal(TreeNode* cur, int count) { if (!cur->left && !cur->right && count == 0) { return true; } if (!cur->left && !cur->right) { return false; } if (cur->left) { count -= cur->left->val; if (traversal(cur->left, count)) { return true; } count += cur->left->val; } if (cur->right) { count -= cur->right->val; if (traversal(cur->right, count)) { return true; } count += cur->right->val; } return false; } bool hasPathSum(TreeNode* root, int targetSum) { if (root == nullptr) { return false; } return traversal(root, targetSum - root->val); } };

第二题

通过中序遍历和后序遍历来构造一棵二叉树,这十分的考验我们对二叉树的理解。首先中序遍历最大的优势就是如果我们确定了根节点,那么我们就可以把一棵树分成左右两颗树,而前序遍历和后续遍历的优势就是找到根节点。所以我们先从后续遍历找到根节点,然后构造出来,再根据值在中序遍历里面找到其对应的位置,然后把中序和后续数组分成左右两个部分,就这么一直循环,直到分到最后一个,然后一个一个的回溯,把结点不停的传到root->left或者root->right,这样也就形成了一颗二叉树

注意一下:构造数组是左闭右开

/** * 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* traversal (vector<int>& inorder, vector<int>& postorder){ if (postorder.size() == 0) { return nullptr; } int rootValue = postorder[postorder.size() - 1]; TreeNode* newNode = new TreeNode(rootValue); if (postorder.size() == 1) { return newNode; } int index = 0; for (int i = 0; i < inorder.size(); i++) { if (rootValue == inorder[i]) { index = i; break; } } vector<int> leftInorder(inorder.begin(), inorder.begin() + index); vector<int> rightInorder(inorder.begin() + index + 1, inorder.end()); postorder.resize(postorder.size() - 1); vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size()); vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end()); newNode->left = traversal(leftInorder, leftPostorder); newNode->right = traversal(rightInorder, rightPostorder); return newNode; } TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) { if (inorder.size() == 0 || postorder.size() == 0) return NULL; return traversal(inorder, postorder); } };

第三题

这是一个对两个二叉树同时操作的题目,这一题的一个难点是如果a树没有的结点b树有我们应该怎么加上去,如果b树没有的a树有怎么办,我们可以在一开始就做一个判断,如果a树没有,那么就返回b树的结点,如果b树没有那么就返回a树的,如果都没有,那么也返回b树的,其实也就是nullptr。然后我们直接在a树上改造就可以。同时操作二叉树的关键就是我们每一次都要传递两个树的参数,保证两个树的同步性

/** * 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* mergeTrees(TreeNode* root1, TreeNode* root2) { if (root1 == nullptr) { return root2; } if (root2 == nullptr) { return root1; } root1->val += root2->val; root1->left = mergeTrees(root1->left, root2->left); root1->right = mergeTrees(root1->right, root2->right); return root1; } };

第四题

这一题我选择的是双指针的方法,这里有几个细节需要注意,就是我们只有遇到了空结点或者两个子树全部都是true我们才会返回true,千万不可以在中途就返回true,这样会导致漏掉情况。反而只要有情况不符合直接返回false。

/** * 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* pre = nullptr; bool isValidBST(TreeNode* root) { if (root == nullptr) { return true; } bool left = isValidBST(root->left); if (pre && pre->val >= root->val) { return false; } pre = root; bool right = isValidBST(root->right); return left && right; } };

第五题

这一题我们有一个比较简单的思路,因为这个是搜索二叉树,所以我们中序遍历的特点就是如果又相同的数,那么一定是会挨在一起的,所以我们其实只需要记录每一次出现的最高频率,如果之后的频率和这个一样,那么就把这个数加入数组之中,如果超过了那么我们就把数组清空,更新一下最高频率,再把这个数放入我们新的数组之中。同时,每一次遇到新的数,我们也要重置一下cnt的值,计为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 cnt = 0; TreeNode* pre = nullptr; vector<int> res; int maxCount = 0; vector<int> findMode(TreeNode* root) { if (root == nullptr) { return res; } findMode(root->left); if (pre == nullptr) { cnt = 1; }else if (pre != nullptr && root->val == pre->val) { cnt++; } else { cnt = 1; } pre = root; if (cnt == maxCount) { res.push_back(root->val); } if (cnt > maxCount) { res.clear(); maxCount = cnt; res.push_back(root->val); } findMode(root->right); return res; } };

第六题

最近的公共祖先它的关键点就是如果找到了结点,那么就一层一层的返回。而从底到根的遍历方式只有后序遍历,对于一个结点是不是返回,返回什么,取决于它的左子树和右子树返回的值。不过我还想强调一个就是关于我们处理结点的地方,处理结点的地方即使是后序遍历可能大家也发现了有的会放在前面,这个是我们对一个结点的最开始的判断,并不是后序遍历的那个对根节点的处理。最开始的if判断是确定我们什么时候返回,而真正对根节点的操作是决定返回什么值。

/** * 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) { if(root == NULL) { return root; } if (root == p || root == q) { return root; } TreeNode* left = lowestCommonAncestor(root->left, p, q); TreeNode* right = lowestCommonAncestor(root->right, p, q); if (left != nullptr && right != nullptr) { return root; } else if (left != nullptr && right == nullptr) { return left; } else if (left == nullptr && right != nullptr) { return right; } else { return nullptr; } } };

总结

本篇文章主要是针对递归的方式进行算法分析,希望可以帮助到大家~~~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/4 4:01:33

02-01-原理篇-Unity原生AssetBundle原理深度解析

Unity 原生 AssetBundle 原理深度解析 篇章&#xff1a;02-原理篇 基础 阅读时间&#xff1a;约 40 分钟 前置知识&#xff1a;了解 Unity 基本资源加载方式 一、引言 AssetBundle&#xff08;简称 AB 包&#xff09;是 Unity 资源管理的基石。理解它的底层原理&#xff0c;是…

作者头像 李华
网站建设 2026/7/4 4:01:33

02-02-原理篇-Unity Addressable Assets原理深度解析

Unity Addressable Assets 原理深度解析 篇章&#xff1a;02-原理篇 基础 阅读时间&#xff1a;约 40 分钟 前置知识&#xff1a;了解 Unity 基本资源加载方式 一、引言 Addressable Assets System&#xff08;简称 Addressables&#xff09;是 Unity 官方提供的资源管理系统…

作者头像 李华
网站建设 2026/7/4 3:56:31

【计算机Java毕业设计案例】汽车配件出入库与销售结算管理系统的设计与实现 基于 SpringBoot 的汽配销售数据可视化分析系统(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/4 3:55:55

了解 风控和TLS

一.熟悉风控类型 1.1 风控等级 初级风控 UA信息&#xff0c;插件信息&#xff0c;屏幕分辨率&#xff0c;验证码&#xff0c;ip封禁 中级风控 显卡配置&#xff0c;canvas指纹&#xff0c;权限指纹 高级风控 鼠标轨迹&#xff0c;函数执行次数 1.2 风控总体来说就是分控…

作者头像 李华
网站建设 2026/7/4 3:55:30

Kimi LeetCode 3455. 最短匹配子字符串 Go实现

LeetCode 3455. 最短匹配子字符串 — Go 实现&#xff08;可直接提交&#xff09;核心思路将 p 按 * 分割为 left * mid * right 三部分。用 KMP 分别找出三者在 s 中的所有匹配位置&#xff0c;然后用双指针枚举 mid 的每个出现位置&#xff0c;寻找最靠右的合法 left 和最靠左…

作者头像 李华
网站建设 2026/7/4 3:55:20

毕设还剩 30 天?这份倒排计划表,照着做或直接找人做都来得及

毕设还剩 30 天&#xff1f;这份倒排计划表&#xff0c;照着做或直接找人做都来得及目标读者&#xff1a;时间紧、想毕业、正在考虑要不要花钱买进度的同学。 这篇既是自救计划&#xff0c;也是你找我做方案时的标准排期参考。一、30 天能不能搞定&#xff1f;能&#xff0c;但…

作者头像 李华