day12

day12

404. 左叶子之和

力扣题目链接

题目

给定二叉树的根节点 root,返回所有左叶子之和。

示例 1:

Untitled

输入: root = [3,9,20,null,null,15,7] 
输出: 24 
解释: 在这个二叉树中,有两个左叶子,分别是 915,所以返回 24

示例 2:

输入: root = [1]
输出: 0

提示:

节点数在 [1, 1000] 范围内
-1000 <= Node.val <= 1000

递归解法

思路

  • 递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和
  1. 确定递归函数的参数和返回值:判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int使用题目中给出的函数就可以了。

  2. 确定终止条件

    if (root == null) {
                return 0;
            }
    
  3. 确定单层递归的逻辑:当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。

    				int leftValue = sumOfLeftLeaves(root.left); // 左
            int rightValue = sumOfLeftLeaves(root.right); // 右
            int midValue = 0;
            if (root.left != null && root.left.left == null && root.left.right == null) {
                midValue = root.left.val;
            }
            int sum = midValue + leftValue + rightValue; // 中
            return sum;
    

代码实现

/**
 * https://leetcode-cn.com/problems/sum-of-left-leaves/
 *
 * @author xiexu
 * @create 2022-03-11 10:28 AM
 */
public class _404_左叶子之和 {

    public int sumOfLeftLeaves(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftValue = sumOfLeftLeaves(root.left); // 左
        int rightValue = sumOfLeftLeaves(root.right); // 右
        int midValue = 0;
        if (root.left != null && root.left.left == null && root.left.right == null) {
            midValue = root.left.val;
        }
        int sum = midValue + leftValue + rightValue; // 中
        return sum;
    }

}

迭代解法 - 前序

代码实现

/**
 * https://leetcode-cn.com/problems/sum-of-left-leaves/
 *
 * @author xiexu
 * @create 2022-03-11 10:28 AM
 */
public class _404_左叶子之和_前序迭代 {

    public int sumOfLeftLeaves(TreeNode root) {
        if (root == null) {
            return 0;
        }
        Stack<TreeNode> stack = new Stack<>();
        int sum = 0; // 左叶子节点之和
        stack.add(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            if (node.left != null && node.left.left == null && node.left.right == null) {
                sum += node.left.val;
            }
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
        return sum;
    }

}

迭代解法 - 层序

代码实现

/**
 * https://leetcode-cn.com/problems/sum-of-left-leaves/
 *
 * @author xiexu
 * @create 2022-03-11 10:28 AM
 */
public class _404_左叶子之和_层序迭代 {

    public int sumOfLeftLeaves(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        int sum = 0; // 左叶子节点之和
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (node.left != null && node.left.left == null && node.left.right == null) {
                sum += node.left.val;
            }
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        return sum;
    }

}

513. 找树左下角的值

力扣题目链接

题目

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

示例 1:

Untitled

输入: root = [2,1,3]
输出: 1

示例 2:

Untitled

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7

提示:

二叉树的节点个数的范围是 [1,10^4]
-2^31 <= Node.val <= 2^31 - 1

递归解法

思路

如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。

那么如何找最左边的呢?可以使用前序遍历,这样才会优先搜索左边,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。

  1. 确定递归函数的参数和返回值:参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。

    1. 本题还需要类里的两个全局变量,MaxDepth 用来记录最大深度,value 记录最大深度最左节点的数值。
    		private int MaxDepth = 0; // 最大深度
        private int value = 0; // 左下角的值
    		public void findLeftValue(TreeNode root, int depth)
    
  2. 确定终止条件:当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。

    				if (root == null) {
                return;
            }
            if (root.left == null && root.right == null) {
                if (depth > MaxDepth) {
                    MaxDepth = depth; // 更新最大深度
                    value = root.val; // 最大深度最左面的数值
                }
            }
    
  3. 确定单层递归的逻辑:在找最大深度的时候,递归的过程中依然要使用回溯

    				if (root.left != null) {
                findLeftValue(root.left, depth + 1);
            }
            if (root.right != null) {
                findLeftValue(root.right, depth + 1);
            }
    

代码实现

/**
 * https://leetcode-cn.com/problems/find-bottom-left-tree-value/
 *
 * @author xiexu
 * @create 2022-03-11 10:58 AM
 */
public class _513_找树左下角的值_递归 {

    private int MaxDepth = 0; // 最大深度
    private int value = 0; // 左下角的值

    public int findBottomLeftValue(TreeNode root) {
        value = root.val;
        findLeftValue(root, 0);
        return value;
    }

    public void findLeftValue(TreeNode root, int depth) {
        if (root == null) {
            return;
        }
        if (root.left == null && root.right == null) {
            if (depth > MaxDepth) {
                MaxDepth = depth; // 更新最大深度
                value = root.val; // 最大深度最左面的数值
            }
        }
        if (root.left != null) {
            findLeftValue(root.left, depth + 1);
        }
        if (root.right != null) {
            findLeftValue(root.right, depth + 1);
        }
    }

}

迭代解法

思路

  • 本题使用层序遍历再合适不过了,比递归要好理解的多!
  • 只需要记录最后一行第一个节点的数值就可以了。

代码实现

/**
 * https://leetcode-cn.com/problems/find-bottom-left-tree-value/
 *
 * @author xiexu
 * @create 2022-03-11 10:58 AM
 */
public class _513_找树左下角的值 {

    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        int res = 0;
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            int n = queue.size();
            for (int i = 0; i < n; i++) {
                TreeNode node = queue.poll();
                if (i == 0) {
                    res = node.val;
                }
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
        }
        return res;
    }

}

112. 路径总和

力扣题目链接

题目

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。

叶子节点 是指没有子节点的节点。

示例 1:

Untitled

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

示例 2:

Untitled

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3:

输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。

提示:

树中节点的数目在范围 [0, 5000]-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

递归解法

递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

  • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(113. 路径总和 II
  • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。(236. 二叉树的最近公共祖先 )
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)

Untitled

  1. 确定递归函数的参数和返回值:图中可以看出,遍历的路线,并不要遍历整棵树,所以递归函数需要返回值,可以用bool类型表示。

    public boolean hasPathSum(TreeNode root, int targetSum)
    
  2. 确定终止条件:

    1. 首先计数器如何统计这一条路径的和呢?
    2. 不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。
    3. 如果最后count == 0,同时到了叶子节点的话,说明找到了目标和。
    4. 如果遍历到了叶子节点,count不为0,就是没找到。
    				// 叶子节点
            if (root.left == null && root.right == null) {
                return targetSum == 0;
            }
    
  3. 确定单层递归的逻辑

    1. 因为终止条件是判断叶子节点,所以递归的过程中就不要让空节点进入递归了。
    2. 递归函数是有返回值的,如果递归函数返回true,说明找到了合适的路径,应该立刻返回。
    			if (root.left != null) {
                boolean left = hasPathSum(root.left, targetSum);
                if (left) { // 已经找到
                    return true;
                }
            }
            if (root.right != null) {
                boolean right = hasPathSum(root.right, targetSum);
                if (right) { // 已经找到
                    return true;
                }
            }
            return false;
    

代码实现

/**
 * https://leetcode-cn.com/problems/path-sum/
 *
 * @author xiexu
 * @create 2022-03-11 1:14 PM
 */
public class _112_路径总和 {

    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        targetSum -= root.val;
        // 叶子节点
        if (root.left == null && root.right == null) {
            return targetSum == 0;
        }
        if (root.left != null) {
            boolean left = hasPathSum(root.left, targetSum);
            if (left) { // 已经找到
                return true;
            }
        }
        if (root.right != null) {
            boolean right = hasPathSum(root.right, targetSum);
            if (right) { // 已经找到
                return true;
            }
        }
        return false;
    }

}

迭代解法

代码实现

/**
 * https://leetcode-cn.com/problems/path-sum/
 *
 * @author xiexu
 * @create 2022-03-11 1:14 PM
 */
public class _112_路径总和_迭代 {

    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<Integer> stack2 = new Stack<>();
        stack1.push(root);
        stack2.push(root.val);
        while (!stack1.isEmpty()) {
            TreeNode node = stack1.pop();
            Integer sum = stack2.pop();
            // 如果该节点是叶子节点了,同时该节点的路径数值等于sum,那么就返回true
            if (node.left == null && node.right == null && sum == targetSum) {
                return true;
            }
            // 右节点,压进去一个节点的时候,将该节点的路径数值也记录下来
            if (node.right != null) {
                stack1.push(node.right);
                stack2.push(node.right.val + sum);
            }
            // 左节点,压进去一个节点的时候,将该节点的路径数值也记录下来
            if (node.left != null) {
                stack1.push(node.left);
                stack2.push(node.left.val + sum);
            }
        }
        return false;
    }

}

113. 路径总和 II

力扣题目链接

题目

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:

Untitled

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:

Untitled

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

提示:

树中节点总数在范围 [0, 5000]-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000

思路

  • 路径总和ii要遍历整个树,找到所有路径,所以递归函数不要返回值!

Untitled

代码实现

/**
 * https://leetcode-cn.com/problems/path-sum-ii/
 *
 * @author xiexu
 * @create 2022-03-11 3:29 PM
 */
public class _113_路径总和_II {

    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        LinkedList<Integer> path = new LinkedList<>();
        preorderdfs(root, targetSum, res, path);
        return res;
    }

    public void preorderdfs(TreeNode root, int targetSum, List<List<Integer>> res, List<Integer> path) {
        path.add(root.val);
        // 叶子节点
        if (root.left == null && root.right == null) {
            // 找到了和为 targetsum 的路径
            if (targetSum - root.val == 0) {
                res.add(new ArrayList<>(path));
            }
            // 如果和不为 targetsum,直接返回
            return;
        }

        if (root.left != null) {
            preorderdfs(root.left, targetSum - root.val, res, path);
            path.remove(path.size() - 1); // 回溯
        }
        if (root.right != null) {
            preorderdfs(root.right, targetSum - root.val, res, path);
            path.remove(path.size() - 1); // 回溯
        }
    }

}

654. 最大二叉树

力扣题目链接

题目

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

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

示例 1:

Untitled

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

Untitled

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

提示:

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

思路

  • 我们肯定要遍历数组把找到最大值maxVal,把根节点root做出来,然后对maxVal左边的数组和右边的数组进行递归调用,作为root的左右子树。
  • 按照题目给出的例子,输入的数组为[3,2,1,6,0,5],对于整棵树的根节点来说,其实在做这件事:
TreeNode constructMaximumBinaryTree([3,2,1,6,0,5]) {
    // 找到数组中的最大值
    TreeNode root = new TreeNode(6);
    // 递归调用构造左右子树
    root.left = constructMaximumBinaryTree([3,2,1]);
    root.right = constructMaximumBinaryTree([0,5]);
    return root;
}
  • 再详细一点,就是如下伪码:
TreeNode constructMaximumBinaryTree(int[] nums) {
    if (nums is empty) return null;
    // 找到数组中的最大值
    int maxVal = Integer.MIN_VALUE;
    int index = 0;
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] > maxVal) {
            maxVal = nums[i];
            index = i;
        }
    }

    TreeNode root = new TreeNode(maxVal);
    // 递归调用构造左右子树
    root.left = constructMaximumBinaryTree(nums[0..index-1]);
    root.right = constructMaximumBinaryTree(nums[index+1..nums.length-1]);
    return root;
}
  • 看懂了吗?对于每个根节点,只需要找到当前nums中的最大值和对应的索引,然后递归调用左右数组构造左右子树即可

代码实现

/**
 * https://leetcode-cn.com/problems/maximum-binary-tree/
 *
 * @author xiexu
 * @create 2022-03-11 4:00 PM
 */
public class _654_最大二叉树 {

    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return build(nums, 0, nums.length - 1);
    }

    /**
     * 将 nums[lo..hi] 构造成符合条件的树,返回根节点
     */
    public TreeNode build(int[] nums, int lo, int hi) {
        if (lo > hi) {
            return null;
        }

        // 找到数组中的最大值和对应的索引
        int index = -1;
        int maxVal = Integer.MIN_VALUE;
        for (int i = lo; i <= hi; i++) {
            if (maxVal < nums[i]) {
                index = i;
                maxVal = nums[i];
            }
        }

        TreeNode root = new TreeNode(maxVal);
        // 递归调用构造左右子树
        root.left = build(nums, lo, index - 1);
        root.right = build(nums, index + 1, hi);

        return root;
    }

}

105. 从前序与中序遍历序列构造二叉树

力扣题目链接

题目

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

Untitled

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均 无重复 元素
inorder 均出现在 preorder
preorder 保证 为二叉树的前序遍历序列
inorder 保证 为二叉树的中序遍历序列

思路

  • preorder 和  inorder 数组中的元素分布有如下特点:

Untitled

  • 找到根节点是很简单的,前序遍历的第一个值preorder[0]就是根节点的值,关键在于如何通过根节点的值,将preorderpostorder数组划分成两半,构造根节点的左右子树?
  • 换句话说,对于以下代码中的?部分应该填入什么:
/* 主函数 */
TreeNode buildTree(int[] preorder, int[] inorder) {
    return build(preorder, 0, preorder.length - 1,
                 inorder, 0, inorder.length - 1);
}

/* 
   若前序遍历数组为 preorder[preStart..preEnd],
   后续遍历数组为 postorder[postStart..postEnd],
   构造二叉树,返回该二叉树的根节点 
*/
TreeNode build(int[] preorder, int preStart, int preEnd, 
               int[] inorder, int inStart, int inEnd) {
    // root 节点对应的值就是前序遍历数组的第一个元素
    int rootVal = preorder[preStart];
    // rootVal 在中序遍历数组中的索引
    int index = 0;
    for (int i = inStart; i <= inEnd; i++) {
        if (inorder[i] == rootVal) {
            index = i;
            break;
        }
    }

    TreeNode root = new TreeNode(rootVal);
    // 递归构造左右子树
    root.left = build(preorder, ?, ?,
                      inorder, ?, ?);

    root.right = build(preorder, ?, ?,
                       inorder, ?, ?);
    return root;
}
  • 对于代码中的rootValindex变量,就是下图这种情况:

Untitled

  • 现在我们来看图做填空题,下面这几个问号处应该填什么:
root.left = build(preorder, ?, ?,
                  inorder, ?, ?);

root.right = build(preorder, ?, ?,
                   inorder, ?, ?);
  • 对于左右子树对应的inorder数组的起始索引和终止索引比较容易确定:

Untitled

root.left = build(preorder, ?, ?,
                  inorder, inStart, index - 1);

root.right = build(preorder, ?, ?,
                   inorder, index + 1, inEnd);
  • 对于preorder数组呢?如何确定左右数组对应的起始索引和终止索引 ?
  • 这个可以通过左子树的节点数推导出来,假设左子树的节点数为leftSize,那么preorder数组上的索引情况是这样的:

Untitled

  • 看着这个图就可以把preorder对应的索引写进去了:
int leftSize = index - inStart;

root.left = build(preorder, preStart + 1, preStart + leftSize,
                  inorder, inStart, index - 1);

root.right = build(preorder, preStart + leftSize + 1, preEnd,
                   inorder, index + 1, inEnd);

代码实现

/**
 * https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
 *
 * @author xiexu
 * @create 2022-03-11 4:13 PM
 */
public class _105_从前序与中序遍历序列构造二叉树 {

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    }

    /**
     * 若前序遍历数组为 preorder[preStart..preEnd],
     * 中序遍历数组为 inorder[inStart..inEnd],
     * 构造二叉树,返回该二叉树的根节点
     */
    public TreeNode build(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
        if (preStart > preEnd) {
            return null;
        }
        // root 节点对应的值就是前序遍历数组的第一个元素
        int rootVal = preorder[preStart];

        // rootVal 在中序遍历数组中的索引
        int index = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == rootVal) {
                index = i;
                break;
            }
        }

        // 先构造出当前根节点
        TreeNode root = new TreeNode(rootVal);
        // 左子树的节点个数
        int leftSize = index - inStart;
        // 递归构造左右子树
        root.left = build(preorder, preStart + 1, preStart + leftSize, inorder, inStart, index - 1);
        root.right = build(preorder, preStart + leftSize + 1, preEnd, inorder, index + 1, inEnd);
        return root;
    }

}

106. 从中序与后序遍历序列构造二叉树

力扣题目链接

题目

给定两个整数数组 inorderpostorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例 1:

Untitled

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

示例 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

提示:

1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder 和 postorder 都由 不同 的值组成
postorder 中每一个值都在 inorder 中
inorder 保证是树的中序遍历
postorder 保证是树的后序遍历

思路

  • preorderinorder 数组中的元素分布有如下特点:

Untitled

  • 这道题和上一题的关键区别是,后序遍历和前序遍历相反,根节点对应的值为postorder的最后一个元素
  • 整体的算法框架和上一题非常类似,我们依然写一个辅助函数build
TreeNode buildTree(int[] inorder, int[] postorder) {
    return build(inorder, 0, inorder.length - 1,
                 postorder, 0, postorder.length - 1);
}

TreeNode build(int[] inorder, int inStart, int inEnd,
               int[] postorder, int postStart, int postEnd) {
    // root 节点对应的值就是后序遍历数组的最后一个元素
    int rootVal = postorder[postEnd];
    // rootVal 在中序遍历数组中的索引
    int index = 0;
    for (int i = inStart; i <= inEnd; i++) {
        if (inorder[i] == rootVal) {
            index = i;
            break;
        }
    }

    TreeNode root = new TreeNode(rootVal);
    // 递归构造左右子树
    root.left = build(preorder, ?, ?,
                      inorder, ?, ?);

    root.right = build(preorder, ?, ?,
                       inorder, ?, ?);
    return root;
}
  • 现在postoderinorder对应的状态如下:

Untitled

  • 我们可以按照上图将问号处的索引正确填入:
int leftSize = index - inStart;

root.left = build(inorder, inStart, index - 1,
                  postorder, postStart, postStart + leftSize - 1);

root.right = build(inorder, index + 1, inEnd,
                   postorder, postStart + leftSize, postEnd - 1);

代码实现

/**
 * https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
 *
 * @author xiexu
 * @create 2022-03-11 3:51 PM
 */
public class _106_从中序与后序遍历序列构造二叉树 {

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        return build(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1);
    }

    /**
     * 后序遍历数组为 postorder[postStart..postEnd],
     * 中序遍历数组为 inorder[inStart..inEnd],
     * 构造二叉树,返回该二叉树的根节点
     */
    public TreeNode build(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {
        if (inStart > inEnd) {
            return null;
        }
        // root 节点对应的值就是后序遍历数组的最后一个元素
        int rootVal = postorder[postEnd];
        // rootVal 在中序遍历数组中的索引
        int index = 0;
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == rootVal) {
                index = i;
                break;
            }
        }

        // 先构造出当前根节点
        TreeNode root = new TreeNode(rootVal);
        // 左子树的节点个数
        int leftSize = index - inStart;
        root.left = build(inorder, inStart, index - 1, postorder, postStart, postStart + leftSize - 1);
        root.right = build(inorder, index + 1, inEnd, postorder, postStart + leftSize, postEnd - 1);
        return root;
    }

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿小羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值