经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 编程经验 » 查看文章
LeetCode654. 最大二叉树
来源:cnblogs  作者:Tomorrowland_D  时间:2024/7/29 9:24:38  对本文有异议

题目链接:https://leetcode.cn/problems/maximum-binary-tree/description/

题目叙述

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。

示例 1:

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:

  • [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    • [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
      • 空数组,无子节点。
      • [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
        • 空数组,无子节点。
        • 只有一个元素,所以子节点是一个值为 1 的节点。
    • [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
      • 只有一个元素,所以子节点是一个值为 0 的节点。
      • 空数组,无子节点。

示例 2:

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

提示:

1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums 中的所有整数 互不相同

思路:

构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树。

我们来走一下递归的三步法:

  1. 递归函数的参数和返回值:返回值明显为TreeNode的节点类型,参数我们需要传入一个数组

  2. 递归结束的条件:题目中说了输入的数组大小一定是大于等于1的,所以我们不用考虑小于1的情况,那么当递归遍历的时候,如果传入的数组大小为1,说明遍历到了叶子节点了。

    那么应该定义一个新的节点,并把这个数组的数值赋给新的节点,然后返回这个节点。 这表示一个数组大小是1的时候,构造了一个新的节点,并返回。

  1. TreeNode* node = new TreeNode(0);
  2. if (nums.size() == 1) {
  3. node->val = nums[0];
  4. return node;
  5. }

3.递归的单层逻辑:

我们需要找出这个数组中的最大值,然后对这个数组进行分割,最大值左边的数组来构造左子树,最大值右边的数组来构造右子树,不过在此之前,我们还得找到最大值和最大值所对应的下标

  1. //找到了这个数组中的最大的元素和最大元素所在的下标
  2. int maxValue = 0;
  3. int index = 0;
  4. for (int i = 0; i < nums.size(); i++) {
  5. if (nums[i] > maxValue) {
  6. index = i;
  7. maxValue = nums[i];
  8. }
  9. }
  10. //对根节点进行赋值
  11. node->val = maxValue;

然后就是对根节点node的左子树和右子树进行构造的过程,我们可以使用两个数组,来存储最大值左边的序列和最大值右边的序列

  1. if (index >= 1) {
  2. //因为vector的拷贝构造函数是左开右闭的逻辑
  3. vector<int> newVec(nums.begin(), nums.begin() + index);
  4. node->left = constructMaximumBinaryTree(newVec);
  5. }
  6. //确保右边子树的元素个数≥1
  7. if ((nums.size() - 1) - index > 0) {
  8. vector<int> newVec(nums.begin() + index + 1, nums.end());
  9. node->right = constructMaximumBinaryTree(newVec);
  10. }
  11. return node;

这几步做完以后,基本就完成了

  1. //最大二叉树
  2. class Solution {
  3. public:
  4. TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
  5. TreeNode* node = new TreeNode(0);
  6. if (nums.size() == 1) {
  7. node->val = nums[0];
  8. return node;
  9. }
  10. //找到了这个数组中的最大的元素和最大元素所在的下标
  11. int maxValue = 0;
  12. int index = 0;
  13. for (int i = 0; i < nums.size(); i++) {
  14. if (nums[i] > maxValue) {
  15. index = i;
  16. maxValue = nums[i];
  17. }
  18. }
  19. //对根节点进行赋值
  20. node->val = maxValue;
  21. //对左子树进行构造(确保左边数组的元素个数≥1)
  22. if (index >= 1) {
  23. vector<int> newVec(nums.begin(), nums.begin() + index);
  24. node->left = constructMaximumBinaryTree(newVec);
  25. }
  26. //确保右边子树的元素个数≥1
  27. if ((nums.size() - 1) - index > 0) {
  28. vector<int> newVec(nums.begin() + index + 1, nums.end());
  29. node->right = constructMaximumBinaryTree(newVec);
  30. }
  31. return node;
  32. }
  33. };

进阶

我们可以不适用额外的数组空间,我们可以直接对传入的数组的下标进行操作

  1. class Solution {
  2. public:
  3. TreeNode* traversal(vector<int> &nums,int left,int right){
  4. //当左区间≥右区间,就返回
  5. if(left>=right) return nullptr;
  6. //记录最大值的下标
  7. int maxValueIndex=left;
  8. for(int i=left+1;i<right;i++){
  9. if(nums[i]>nums[maxValueIndex]) maxValueIndex=i;
  10. }
  11. //构造根节点
  12. TreeNode* node=new TreeNode(nums[maxValueIndex]);
  13. //构造左子树和右子树
  14. node->left=traversal(nums,left,maxValueIndex);
  15. node->right=traversal(nums,maxValueIndex+1,right);
  16. //返回根节点
  17. return node;
  18. }
  19. TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
  20. return traversal(nums,0,nums.size());
  21. }
  22. };

总结

注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下标索引直接在原数组上操作,这样可以节约时间和空间上的开销。

什么时候递归函数前面加if,什么时候不加if?

其实就是不同代码风格的实现,一般情况来说:如果让空节点(空指针)进入递归,就不加if,如果不让空节点进入递归,就加if限制一下, 终止条件也会相应的调整。

原文链接:https://www.cnblogs.com/Tomorrowland/p/18328894

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号