654. 最大二叉树
给定一个不重复的整数数组 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 的节点。
- 空数组,无子节点。
- [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
示例 2:
输入:nums = [3,2,1]
输出:[3,null,2,null,1]
思考
其实这本身就是一个递归而且题目也描述的较为清楚
首先写个一个函数getMaxIndex(int[] nums,int left,int right)
用来获取nums函数在left到right区间内的最大值的索引。
递归前的初始化:
获取nums函数的最大值的索引,构建根节点
初始化root的左右子树在数组中的区间rootleft0,rootleft1,rootright0,rootright1,并初始化为-1,其-1代表其根节点不存在左右子树
接下来判断是否存在左右子树
- 如果根节点等于 0 ,根节点不存在左子树
- 如果根节点等于nums.length-1,根节点不存在右子树
如果存在左右子树对其进行赋值
进行递归constructToTree(root,nums,rootleft0,rootleft1,rootright0,rootright1)
首先不需要返回值,因为root是引用变量。
其参数需要节点,数组、其节点的左右子树的范围。
递归结束条件,其不存在左右子树即rootleft0==-1&&rootright0==-1
初始化left=null,right=null
如果根节点存在左子树
- 获取左子树最大值的索引 leftMaxindex 指向的值构建 root.left
- 接下来我们认为leftMaxindex 指向的值作为左子树的根节点 leftTreeRoot
- 我们需要判断根节点leftTreeRoot是否存在左右子树
- 存在左右子树
- 进行递归
- 只存在右子树
- 进行递归
- 只存在左子树
- 进行递归
注意:其不存在左右子树不用操作了
如果根节点存在右子树
- 与上类似不在赘述
public static TreeNode constructMaximumBinaryTree(int[] nums) {
int maxIndex = getMaxIndex(nums,0,nums.length-1);
TreeNode root = new TreeNode(nums[maxIndex]);
int rootleft0 = -1;
int rootleft1 = -1;
int rootright0 = -1;
int rootright1 = -1;
if(maxIndex>0){
rootleft0 = 0;
rootleft1 = maxIndex-1;
}
if(maxIndex<nums.length-1){
rootright0 = maxIndex+1;
rootright1 = nums.length-1;
}
constructToTree(root,nums,rootleft0,rootleft1,rootright0,rootright1);
return root;
}
private static void constructToTree(TreeNode root, int[] nums, int rootleft0, int rootleft1, int rootright0, int rootright1) {
if(rootleft0==-1&&rootright0==-1) return;
TreeNode left = null;
TreeNode right = null;
// 存在左子树
if(rootleft0!=-1){
int leftMaxIndex = getMaxIndex(nums, rootleft0, rootleft1);
left = new TreeNode(nums[leftMaxIndex]);
root.left = left;
int hasleft = 1;
int hasright = 1;
if(leftMaxIndex ==rootleft0) hasleft=0;
if(leftMaxIndex ==rootleft1) hasright =0;
// 左子树的最大值作为根节点 有左右子树
if(hasleft==1&&hasright==1){
constructToTree(root.left,nums,rootleft0,leftMaxIndex-1,leftMaxIndex+1,rootleft1);
}
// 左子树的最大值作为根节点只有左子树
if(hasleft==1&&hasright==0){
constructToTree(root.left,nums,rootleft0,leftMaxIndex-1,-1,-1);
}
// 只有右子树
if(hasleft==0&&hasright==1) {
constructToTree(root.left,nums,-1,-1,leftMaxIndex+1,rootleft1);
}
//既没有左子树又没有右子树 不需要操作
}
if(rootright0!=-1){
int rightMaxIndex = getMaxIndex(nums, rootright0, rootright1);
right = new TreeNode(nums[rightMaxIndex]);
root.right = right;
int hasleft = 1;
int hasright = 1;
if(rightMaxIndex ==rootright0) hasleft=0;
if(rightMaxIndex ==rootright1) hasright =0;
// 有左右子树
if(hasleft==1&&hasright==1){
constructToTree(root.right,nums,rootright0,rightMaxIndex-1,rightMaxIndex+1,rootright1);
}
// 只有左子树
if(hasleft==1&&hasright==0){
constructToTree(root.right,nums,rootright0,rightMaxIndex-1,-1,-1);
}
// 只有右子树
if(hasleft==0&&hasright==1) {
constructToTree(root.right,nums,-1,-1,rightMaxIndex+1,rootright1);
}
//既没有左子树又没有右子树 不需要操作
}
}
public static int getMaxIndex(int[] nums,int left,int right){
int max = nums[left];
int index = left;
for (int i = left; i<=right;i++){
if(nums[i]>max) {
max = nums[i];
index = i;
}
}
return index;
}