二叉树刷题篇 最大二叉树 and 合并二叉树

Posted 归宅观察部

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树刷题篇 最大二叉树 and 合并二叉树相关的知识,希望对你有一定的参考价值。

654.最大二叉树

给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:二叉树的根是数组 nums 中的最大元素。左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。返回有给定数组 nums 构建的 最大二叉树 。

https://leetcode-cn.com/problems/maximum-binary-tree/
这题与昨天做的根据中序与后序遍历数组构造二叉树思路基本一样,做题的确也是有套路的,会一道就是会十道(x) 。

递归法即可完美解决。这里注意要判断maxValueIndex的值,保证切割出来的左右数组大小大于0。比如[3,2,1]这个数组再去切分,会出现[]的左数组,再对这个左数组进行构造,会进入死循环。如果想解除这个死循环需要在函数前面进行判断,处理nums.size()==0的情况,就很麻烦,因此在迭代时先进行判断排除这种情况是比较方便的。
class Solution {public: TreeNode* constructMaximumBinaryTree(vector<int>& nums) { if(nums.size()==1){ return new TreeNode(nums[0]); } int maxValue=0; int maxValueIndex=0; for(int i=0;i<nums.size();i++){ if(nums[i]>maxValue){ maxValue=nums[i]; maxValueIndex=i; } } TreeNode* root=new TreeNode(maxValue); if (maxValueIndex > 0) { vector<int> leftnums(nums.begin(),nums.begin()+maxValueIndex); root->left=constructMaximumBinaryTree(leftnums); } if (maxValueIndex < (nums.size() - 1)){ vector<int> rightnums(nums.begin()+maxValueIndex+1,nums.end()); root->right=constructMaximumBinaryTree(rightnums); } return root;
}};
仿照昨天的思路,不在每次递归中创造新的vector,而是用数组的起始结束位置作为参数传入,代码如下。
class Solution {private: // 在左闭右开区间[left, right),构造二叉树 TreeNode* traversal(vector<int>& nums, int left, int right) { if (left >= right) return nullptr; // 这里的判断条件可以改成left == right // 分割点下表:maxValueIndex int maxValueIndex = left; for (int i = left + 1; i < right; ++i) { if (nums[i] > nums[maxValueIndex]) maxValueIndex = i; }
TreeNode* root = new TreeNode(nums[maxValueIndex]);
// 左闭右开:[left, maxValueIndex) root->left = traversal(nums, left, maxValueIndex);
// 左闭右开:[maxValueIndex + 1, right) root->right = traversal(nums, maxValueIndex + 1, right);
return root; }public: TreeNode* constructMaximumBinaryTree(vector<int>& nums) { return traversal(nums, 0, nums.size()); }};//代码来自公众号 代码随想录 作者为Carl

617.合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

https://leetcode-cn.com/problems/merge-two-binary-trees/
这题乍一看不难,似乎层序遍历+节点数值合并就可以解决,但这样面临一个严重问题,就是在这种情况下必须让空节点也能够入栈(队列),那么就无法使用while(!que.empty())这个条件让循环停止,会陷入死循环。
思来想去,还是先使用递归法吧,看代码:
class Solution {public: TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) { if(root1==NULL&&root2==NULL) return NULL; if(root1!=NULL&&root2==NULL){ TreeNode* node= new TreeNode(root1->val); node->left=mergeTrees(root1->left,NULL); node->right=mergeTrees(root1->right,NULL); return node; } if(root1==NULL&&root2!=NULL){ TreeNode* node= new TreeNode(root2->val); node->left=mergeTrees(NULL,root2->left); node->right=mergeTrees(NULL,root2->right); return node; } else{ TreeNode* node=new TreeNode(root1->val+root2->val); node->left=mergeTrees(root1->left,root2->left); node->right=mergeTrees(root1->right,root2->right); return node; } TreeNode* node= new TreeNode(root1->val+root2->val); node->left=mergeTrees(root1->left,root2->left); node->right=mergeTrees(root1->right,root2->right); return node; }};
这个代码写得,emmmm……很显然内存消耗会比较大,看看Carl大神怎么写的,学习一下。
class Solution {public: TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { if (t1 == NULL) return t2; if (t2 == NULL) return t1; // 重新定义新的节点,不修改原有两个树的结构 TreeNode* root = new TreeNode(0); root->val = t1->val + t2->val; root->left = mergeTrees(t1->left, t2->left); root->right = mergeTrees(t1->right, t2->right); return root; }};//代码来自公众号 代码随想录 作者为Carl
看完的确让人眼前一亮(当然也可能是我太蠢哈哈哈),其实简单地阐述一下就是,假如t1==NULL,那么t1就可以=t2(比我们一个一个节点去判断要好得多)。

当然,这里也提供一下迭代法的代码,和我们最一开始的思路一样,使用两个queue去存储节点,然后一直层序遍历,合并节点。

class Solution {public: TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) { if (t1 == NULL) return t2; if (t2 == NULL) return t1; queue<TreeNode*> que; que.push(t1); que.push(t2); while(!que.empty()) { TreeNode* node1 = que.front(); que.pop(); TreeNode* node2 = que.front(); que.pop(); // 此时两个节点一定不为空,val相加 node1->val += node2->val;
// 如果两棵树左节点都不为空,加入队列 if (node1->left != NULL && node2->left != NULL) { que.push(node1->left); que.push(node2->left); } // 如果两棵树右节点都不为空,加入队列 if (node1->right != NULL && node2->right != NULL) { que.push(node1->right); que.push(node2->right); }
// 当t1的左节点 为空 t2左节点不为空,就赋值过去 if (node1->left == NULL && node2->left != NULL) { node1->left = node2->left; } // 当t1的右节点 为空 t2右节点不为空,就赋值过去 if (node1->right == NULL && node2->right != NULL) { node1->right = node2->right; } } return t1; }};//代码来自公众号 代码随想录 作者为Carl
好,今天是除夕夜,就做到这里,也祝大家除夕快乐!

以上是关于二叉树刷题篇 最大二叉树 and 合并二叉树的主要内容,如果未能解决你的问题,请参考以下文章

二叉树刷题篇镜像二叉树与二叉树深度

二叉树刷题篇平衡二叉树与二叉树的所有路径

二叉树刷题篇(咕)

二叉树刷题篇

二叉树刷题篇(10) 二叉搜索树

二叉树刷题篇层序遍历