Day 16 二叉樹part04

12点不睡觉还想干啥?發表於2024-07-17

513. 找樹左下角的值

這道題與199. 二叉樹的右檢視的思路是相同的。也就可以分為遞迴和迭代兩種方式,對於這兩道題來說,迭代就是使用層序遍歷的方式找到最左或最右的值即可。513這題不同的一點是,只需要找到最底層最左側的值,而不需每一層都儲存。因此考慮使用一個a_depth儲存目前找到最深的結果的深度,只有找到更深的才去更新結果。

class Solution {
    int ans;
    int a_depth;
    public int findBottomLeftValue(TreeNode root) {
        findValue(root, 1);
        return ans;
    }

    public void findValue(TreeNode cur, int depth){
        if(cur == null) return;
        if(depth > a_depth) {
            a_depth = depth;
            ans = cur.val;
        }
        findValue(cur.left, depth + 1);
        findValue(cur.right, depth + 1);
    }
}

112. 路徑總和

我自己的方法和257.二叉樹的所有路徑 做法一致,透過使用一個列表path儲存從root到當前節點的路徑上所有節點,如果當前節點是葉子節點再判斷其和是否等於targetsum即可。很明顯,這個path是沒有必要儲存的,官解的程式碼放在下面了,反正就是優雅,優雅。

class Solution {  //自己寫的醜陋版本,比較類似於二叉樹所有路徑那道題,但我這樣的做法相當於複雜化了,許多東西並不需要儲存。但這種做法對於路徑總和Ⅱ是必要的。
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) return false;
        List<Integer> path = new ArrayList();
        return findPath(root, path, targetSum);
    }
    public boolean findPath(TreeNode cur, List<Integer> path, int targetSum){
        if(cur != null) path.add(cur.val);
        if(cur.left == null && cur.right == null && sum(path) == targetSum) return true;
        if(cur.left != null){
            if(findPath(cur.left, path, targetSum)) return true;
            path.remove(path.size()-1);
        }
        if(cur.right != null){
            if(findPath(cur.right, path, targetSum)) return true;
            path.remove(path.size() - 1);
        }
        return false;
    }

    public int sum(List<Integer> path){
        int ans = 0;
        for(Integer i : path) ans += i;
        return ans;
    }
}


class Solution {  // 官解
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) return false;
        if(root.left == null && root.right == null && root.val == targetSum) return true;
        return hasPathSum(root.left, targetSum - root.val) ||
            	hasPathSum(root.right, targetSum - root.val); 
    }
}

113. 路徑總和 II

會了上一題再做這個就會容易不少

class Solution {
    List<List<Integer>> res = new ArrayList();
    List<Integer> path = new ArrayList();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        getPaths(root, targetSum);
        return res;
    }

    public void getPaths(TreeNode root, int targetSum){
        if(root == null) return;
        path.add(root.val);
        if(root.val == targetSum && root.left == null && root.right == null){
            res.add(new ArrayList(path));
        }

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

106. 從中序與後序遍歷序列構造二叉樹

居然自己沒看題解就寫出來了,哈哈哈哈雖然花的時間很多。主要就是要理清中序和後序遍歷的關係。可以知道,後序遍歷的最後一個節點,一定是根節點,找到這個根節點後,再去中序遍歷中,用它進行分割,就能找到對於該根節點左子樹的節點集合和右子樹的節點集合。同樣的,中序遍歷中左子樹中節點集合的長度與後序遍歷中左子樹中節點集合的長度相同,因此只需要去分割左右子樹的節點集合出來用於遞迴的解決左子樹和右子樹的問題。

class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(inorder.length == 0) return null;
        int mid = postorder[inorder.length-1];  //後序遍歷的最後一個節點為根節點
        int ind = -1;
        for(int i = 0; i < inorder.length; i++){
            if(inorder[i] == mid) {ind = i; break;}  // 找根節點的index
        }
        TreeNode left = buildTree(Arrays.copyOfRange(inorder, 0, ind), Arrays.copyOfRange(postorder, 0, ind));   //函式引數為  左子樹的中序遍歷,左子樹的後序遍歷
        TreeNode right = buildTree(Arrays.copyOfRange(inorder, ind + 1, inorder.length), 
                    Arrays.copyOfRange(postorder, ind, postorder.length-1));
        //函式引數為  右子樹的中序遍歷,右子樹的後序遍歷
        TreeNode cur = new TreeNode(mid, left, right); //左右子樹構建好後,跟根節點構成完整的樹
        return cur;
    }
}

相關文章