代码随想录day16|513找树左下角的值112、113路径总和105、106构造二叉树|01笔记

90 阅读2分钟
  • 513找树左下角的值

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 按照行来找值,那么可以使用层序遍历,每次更新最左面的值。最后保留的就是最后一行的最左面的值。
  • 讲解观后感

  • 用递归法来做的话,就需要一个参数来记录深度,并且要选择左在先的递归法,这样在深度更新时存入的节点数值就是最左面的值。
  • 解题代码

  • 层序
  •     /**
         * Definition for a binary tree node.
         * type TreeNode struct {
         *     Val int
         *     Left *TreeNode
         *     Right *TreeNode
         * }
         */
        func findBottomLeftValue(root *TreeNode) int {
            st := list.New()
            ans := 0
        
            if root!=nil {
                st.PushBack(root)
            }
        
            for st.Len()!=0 {
                len := st.Len()
                for i:=0;i<len;i++ {
                    node := st.Remove(st.Front()).(*TreeNode)
                    if i==0 {
                        ans = node.Val
                    }
                    if node.Left!=nil {
                        st.PushBack(node.Left)
                    }
                    if node.Right!=nil {
                        st.PushBack(node.Right)
                    }
                }
            }
            return ans
        }
    
  • 递归
  •     var depth int   // 全局变量 最大深度
        var res int     // 记录最终结果
        func findBottomLeftValue(root *TreeNode) int {
            depth, res = 0, 0   // 初始化
            dfs(root, 1)
            return res
        }
        
        func dfs(root *TreeNode, d int) {
            if root == nil {
                return
            }
            // 因为先遍历左边,所以左边如果有值,右边的同层不会更新结果
            if root.Left == nil && root.Right == nil && depth < d { 
                depth = d
                res = root.Val
            }
            dfs(root.Left, d+1)   // 隐藏回溯
            dfs(root.Right, d+1)
        }
    
  • 递归回溯表达(C++)
  •     class Solution {
        public:
            int maxDepth = INT_MIN;
            int result;
            void traversal(TreeNode* root, int depth) {
                if (root->left == NULL && root->right == NULL) {
                    if (depth > maxDepth) {
                        maxDepth = depth;
                        result = root->val;
                    }
                    return;
                }
                if (root->left) {
                    depth++;
                    traversal(root->left, depth);
                    depth--; // 回溯
                }
                if (root->right) {
                    depth++;
                    traversal(root->right, depth);
                    depth--; // 回溯
                }
                return;
            }
            int findBottomLeftValue(TreeNode* root) {
                traversal(root, 0);
                return result;
            }
        };
    
  • 112路径总和113路径总和II

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 使用回溯遍历所有叶子结点并计算值(保存路径)
  • 遇到问题

  •     /**
         * Definition for a binary tree node.
         * type TreeNode struct {
         *     Val int
         *     Left *TreeNode
         *     Right *TreeNode
         * }
         */
         var ans [][]int
        
        func pathSum(root *TreeNode, targetSum int) [][]int {
            ans = make([][]int, 0)
            path := []int{}
        
            if root==nil {
                return ans
            }
            serchPath(root, 0, path, targetSum)
            return ans
        
        }
        
        func serchPath(node *TreeNode, sum int,path []int, targetSum int) {
            // if node==nil {
            //     return
            // }
            sum+=node.Val
            path = append(path, node.Val)
            if node.Left==nil&&node.Right==nil {
                if sum==targetSum {
                    ans = append(ans, path)
                }
                return
            }
            if node.Left!=nil {
                serchPath(node.Left, sum, path, targetSum)
            }
            if node.Right!=nil {
                serchPath(node.Right, sum, path, targetSum)
            }
            return
        }
    

image.png

  • 原因:
    不能直接将Path放到ans里面, 因为Path是共享的, 每次遍历子树时都会被修改
  • 解题代码

  •     /**
         * Definition for a binary tree node.
         * type TreeNode struct {
         *     Val int
         *     Left *TreeNode
         *     Right *TreeNode
         * }
         */
         var ans [][]int
        
        func pathSum(root *TreeNode, targetSum int) [][]int {
            ans = make([][]int, 0)
            path := []int{}
        
            if root==nil {
                return ans
            }
            serchPath(root, 0, path, targetSum)
            return ans
        
        }
        
        func serchPath(node *TreeNode, sum int,path []int, targetSum int) {
            // if node==nil {
            //     return
            // }
            sum+=node.Val
            path = append(path, node.Val)
            if node.Left==nil&&node.Right==nil {
                if sum==targetSum {
                    copyPath := make([]int, len(path))
                    for i:=0;i<len(path);i++ {
                        copyPath[i] = path[i]
                    }
                    ans = append(ans, copyPath)
                }
                
                return
            }
            if node.Left!=nil {
                serchPath(node.Left, sum, path, targetSum)
            }
            if node.Right!=nil {
                serchPath(node.Right, sum, path, targetSum)
            }
            return
        }
    
  • 105、106构造二叉树

  • 代码随想录 (programmercarl.com)
  • 讲解观后感

  • 方法是利用后序数组寻找中结点,然后通过中序数组中结点的位置分出左右两个数组,后序根据其长度来区分,再寻找其各自的中结点。用递归实现。
  • 需要注意用中序和后序、前序和中序数组都可以构造出唯一的树,但是用前序和后序不能。因为无法无法确定左右子树的分界。
  • 解题代码

  • golang中可以利用map存储中序遍历的值与位置,方便构建时查找。
  • 中序与后序
  •     var (
            hash map[int]int
        )
        func buildTree(inorder []int, postorder []int) *TreeNode {
            hash = make(map[int]int)
            for i, v := range inorder {  // 用map保存中序序列的数值对应位置
                hash[v] = i
            }
            // 以左闭右闭的原则进行切分
            root := rebuild(inorder, postorder, len(postorder)-1, 0, len(inorder)-1)
            return root
        }
        // rootIdx表示根节点在后序数组中的索引,l, r 表示在中序数组中的前后切分点
        func rebuild(inorder []int, postorder []int, rootIdx int, l, r int) *TreeNode {
            if l > r {    // 说明没有元素,返回空树
                return nil
            }
            if l == r {  // 只剩唯一一个元素,直接返回
                return &TreeNode{Val : inorder[l]}
            }
            rootV := postorder[rootIdx]  // 根据后序数组找到根节点的值
            rootIn := hash[rootV]        // 找到根节点在对应的中序数组中的位置
            root := &TreeNode{Val : rootV}   // 构造根节点
            // 重建左节点和右节点
            root.Left = rebuild(inorder, postorder, rootIdx-(r-rootIn)-1, l, rootIn-1)
            root.Right = rebuild(inorder, postorder, rootIdx-1, rootIn+1, r)
            return root
        }
    
  • 前序与中序
  •     var (
            hash map[int]int
        )
        func buildTree(preorder []int, inorder []int) *TreeNode {
            hash = make(map[int]int, len(inorder))
            for i, v := range inorder {
                hash[v] = i
            }
            root := build(preorder, inorder, 0, 0, len(inorder)-1)  // l, r 表示构造的树在中序遍历数组中的范围
            return root
        }
        func build(pre []int, in []int, root int, l, r int) *TreeNode {
            if l > r {
                return nil
            }
            rootVal := pre[root]  // 找到本次构造的树的根节点
            index := hash[rootVal]  // 根节点在中序数组中的位置
            node := &TreeNode {Val: rootVal}
            node.Left = build(pre, in, root + 1, l, index-1)
            node.Right = build(pre, in, root + (index-l) + 1, index+1, r)
            return node
        }