LeetCode654. 最大二叉树

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

题目叙述

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

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

示例 1:

LeetCode654. 最大二叉树

输入: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:

LeetCode654. 最大二叉树

输入: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的时候,构造了一个新的节点,并返回。

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

3.递归的单层逻辑:

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

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

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

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

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

 //最大二叉树 class Solution { public: 	TreeNode* constructMaximumBinaryTree(vector<int>& nums) { 		TreeNode* node = new TreeNode(0); 		if (nums.size() == 1) { 			node->val = nums[0]; 			return node; 		} 		//找到了这个数组中的最大的元素和最大元素所在的下标 		int maxValue = 0; 		int index = 0; 		for (int i = 0; i < nums.size(); i++) { 			if (nums[i] > maxValue) { 				index = i; 				maxValue = nums[i]; 			} 		} 		//对根节点进行赋值 		node->val = maxValue; 		//对左子树进行构造(确保左边数组的元素个数≥1) 		if (index >= 1) { 			vector<int> newVec(nums.begin(), nums.begin() + index); 			node->left = constructMaximumBinaryTree(newVec); 		} 		//确保右边子树的元素个数≥1 		if ((nums.size() - 1) - index > 0) { 			vector<int> newVec(nums.begin() + index + 1, nums.end()); 			node->right = constructMaximumBinaryTree(newVec); 		} 		return node; 	} }; 

进阶

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

class Solution { public:     TreeNode* traversal(vector<int> &nums,int left,int right){         //当左区间≥右区间,就返回         if(left>=right) return nullptr;         //记录最大值的下标         int maxValueIndex=left;         for(int i=left+1;i<right;i++){             if(nums[i]>nums[maxValueIndex]) maxValueIndex=i;         }         //构造根节点         TreeNode* node=new TreeNode(nums[maxValueIndex]);         //构造左子树和右子树         node->left=traversal(nums,left,maxValueIndex);         node->right=traversal(nums,maxValueIndex+1,right);         //返回根节点         return node;     }     TreeNode* constructMaximumBinaryTree(vector<int>& nums) {         return traversal(nums,0,nums.size());     } }; 

总结

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

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

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

发表评论

评论已关闭。

相关文章