代码随想录算法训练营第十八天|513.寻找树左下角的值、112.路经总和、113.路径总和II、106.从中序与后序序列构造二叉树、105.从前序与中序序列构造

91 阅读3分钟

513.寻找树左下角的值

题目链接:513. 找树左下角的值

思路:通过层序遍历比较简单,但是层序遍历的时候需要从右到左来遍历,最后一个遍历的节点就是树左下角的值。递归遍历也可以,因为不需要处理中间节点,所以只需要保证先左后右的顺序就好,可以看作前序遍历。每次遍历到叶子节点,记录深度,如果深度比当前深度大,更新结果。

层序遍历实现

class Solution {
    public int findBottomLeftValue(TreeNode root) { // 层序遍历
        Queue<TreeNode> que = new LinkedList<>();
        que.add(root);
        int size = 0;
        while (!que.isEmpty()) {
            size = que.size();
            while (size-- > 0) {
                TreeNode node = que.poll();
                if (node.right != null) {
                    que.add(node.right);
                }
                if (node.left != null) {
                    que.add(node.left);
                }
                if (que.isEmpty()) {
                    return node.val;
                }
            }
        }
        return -1;
    }
}

递归遍历实现

class Solution {
    private int maxDeep = -1;
    private int ans = 0;
    public int findBottomLeftValue(TreeNode root) { // 前序递归遍历
        ans = root.val;
        getLeftVal(root, 0);
        return ans;
    }
    public void getLeftVal(TreeNode node, int deep) {
        if (node == null) return;
        if (node.left == null && node.right == null) { // 若为叶子节点
            if (deep > maxDeep) { // 深度比当前最大深度大
                ans = node.val; // 更新结果
                maxDeep = deep;
            }
        }
        getLeftVal(node.left, deep + 1);
        getLeftVal(node.right, deep + 1);
    }
}

112.路经总和

题目链接:112. 路径总和

思路:采用后序递归遍历,当遍历到叶子节点的时候判断是否符合条件,符合条件返回true,不符合条件返回false,只要有一个孩子是true就是true。(注意回溯的过程。)

class Solution {
    private int count = 0;
    public boolean hasPathSum(TreeNode root, int targetSum) { // 后序递归遍历
        if (root == null) return false;
        count += root.val;
        if (root.left == null && root.right == null && count == targetSum) {
            return true;
        }
        boolean left = false;
        if (root.left != null) {
            left = hasPathSum(root.left, targetSum);
            count -= root.left.val;
        }
        boolean right = false;
        if (root.right != null) {
            right = hasPathSum(root.right, targetSum);
            count -= root.right.val;
        }
        return left || right;
    }
}

113.路径总和II

题目链接;113. 路径总和 II

思路:递归遍历,没有处理中节点的操作,(可以看成前序遍历)定义数组来记录路径,每当遍历到叶子节点的时候判断是否符合条件,符合条件就将路径加入到结果中。(注意回溯过程)

class Solution {
    private List<List<Integer>> ans; // 结果
    private List<Integer> path = new ArrayList<>(); // 记录路径
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) { // 递归遍历
        ans = new ArrayList<>();
        if (root == null) return ans;
        getPath(root, targetSum);
        return ans;
    }
    public void getPath(TreeNode node, int count) {
        path.add(node.val); // 路径中加入当前节点
        count -= node.val; // 记录当前节点值
        if (node.left == null && node.right == null && count == 0) { // 符合条件,更新结果
            List<Integer> temp = new ArrayList<>(path);
            ans.add(temp);
            return;
        }
        if (node.left == null && node.right == null) return;
        if (node.left != null) { // 存在左节点,遍历左节点
            getPath(node.left, count);
            path.remove(path.size() - 1); // 回溯
        }
        if (node.right != null) { // 存在右节点,遍历右节点
            getPath(node.right, count);
            path.remove(path.size() - 1); // 回溯
        }
        return;
    }
}

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

题目链接:106. 从中序与后序遍历序列构造二叉树

思路:采用递归的方式不断分割数组,然后构造节点。

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if (postorder.length == 0) return null;
        TreeNode root = new TreeNode(postorder[postorder.length - 1]);
        if (postorder.length == 1) return root; // 如果后序数组只剩一个元素,说明到叶子节点了,直接返回
        // 分割数组
        int index = 0;
        for (;index < inorder.length; index++) {
            if (inorder[index] == root.val) {
                break;
            }
        }
        int[] leftInorder = new int[index];
        int[] leftPostorder = new int[index];
        for (int i = 0; i < index; i++) {
            leftInorder[i] = inorder[i];
            leftPostorder[i] = postorder[i];
        }
        int[] rightInorder = new int[inorder.length - 1 - index];
        int[] rightPostorder = new int[inorder.length - 1 - index];
        for (int i = 0; i < rightInorder.length; i++) {
            rightInorder[i] = inorder[i + index + 1];
            rightPostorder[i] = postorder[i + index];
        }
        TreeNode left = buildTree(leftInorder, leftPostorder);
        TreeNode right = buildTree(rightInorder, rightPostorder);
        root.left = left;
        root.right = right;
        return root;
    }
}

随想录中写法,避免了大量的数组操作,注意区间定义一致。

class Solution {
    Map<Integer, Integer> map;  // 方便根据数值查找位置
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        map = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) { // 用map保存中序序列的数值对应位置
            map.put(inorder[i], i);
        }

        return findNode(inorder,  0, inorder.length, postorder,0, postorder.length);  // 前闭后开
    }
    
    public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd) {
        // 参数里的范围都是前闭后开
        if (inBegin >= inEnd || postBegin >= postEnd) {  // 不满足左闭右开,说明没有元素,返回空树
            return null;
        }
        int rootIndex = map.get(postorder[postEnd - 1]);  // 找到后序遍历的最后一个元素在中序遍历中的位置
        TreeNode root = new TreeNode(inorder[rootIndex]);  // 构造结点
        int lenOfLeft = rootIndex - inBegin;  // 保存中序左子树个数,用来确定后序数列的个数
        root.left = findNode(inorder, inBegin, rootIndex,
                            postorder, postBegin, postBegin + lenOfLeft);
        root.right = findNode(inorder, rootIndex + 1, inEnd,
                            postorder, postBegin + lenOfLeft, postEnd - 1);

        return root;
    }

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

题目链接:105. 从前序与中序遍历序列构造二叉树

思路:与上一题解法相同。

class Solution {
    Map<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i); // map中存放中序数组,方便快速查找根节点位置。
        }
        return getTree(preorder, 0, preorder.length, inorder, 0, inorder.length);
    }
    public TreeNode getTree(int[] preorder, int pStart, int pEnd, int[] inorder, int inStart, int inEnd) {
        if (pStart >= pEnd || inStart >= inEnd) return null; // 没有元素了,返回null
        int rootIndex = map.get(preorder[pStart]); // 根节点在中序数组中的下标
        TreeNode root = new TreeNode(inorder[rootIndex]);
        int leftLen = rootIndex - inStart; // 左孩子数组的长度
        root.left = getTree(preorder, pStart + 1, pStart + 1 + leftLen, inorder, inStart, rootIndex);
        root.right = getTree(preorder, pStart + 1 + leftLen, pEnd, inorder, rootIndex + 1, inEnd);
        return root;
    }
}