代码随想录day20|669修剪二叉搜索树108有序数组转二叉搜索树538二叉搜索树转累加树|01笔记

77 阅读2分钟
  • 669修剪二叉搜索树

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

  • 简单的想法是利用中序遍历得到有序数组,再在数组中去掉区间外的值后重新生成二叉搜索树。这样这道题就类似于另外一道题了。
  • 讲解观后感

  • 递归法遇到界限外节点的处理方法是返回其相应子树。小于界限返回左子树,大于界限返回右子树。直接返回nil会遗失子树上在范围内的值。
  • 迭代法:从根节点向下找到的第一个符合范围内的节点就是新树的根节点,其下的所有节点即是原树中所有存在于区间的节点。
  • 解题代码

  • 递归
  •     // 递归
        func trimBST(root *TreeNode, low int, high int) *TreeNode {
            if root == nil {
                return nil
            }
            if root.Val < low {     //如果该节点值小于最小值,则该节点更换为该节点的右节点值,继续遍历
                right := trimBST(root.Right, low, high)
                return right
            }
            if root.Val > high {    //如果该节点的值大于最大值,则该节点更换为该节点的左节点值,继续遍历
                left := trimBST(root.Left, low, high)
                return left
            }
            root.Left = trimBST(root.Left, low, high)
            root.Right = trimBST(root.Right, low, high)
            return root
        }
    
  • 迭代
  •     // 迭代
        func trimBST(root *TreeNode, low int, high int) *TreeNode {
            if root == nil {
                return nil
            }
            // 处理 root,让 root 移动到[low, high] 范围内,注意是左闭右闭
            for root != nil && (root.Val < low || root.Val > high) {
                if root.Val < low {
                    root = root.Right
                } else {
                    root = root.Left
                }
            }
            cur := root
            // 此时 root 已经在[low, high] 范围内,处理左孩子元素小于 low 的情况(左节点是一定小于 root.Val,因此天然小于 high)
            for cur != nil {
                for cur.Left != nil && cur.Left.Val < low {
                    cur.Left = cur.Left.Right
                }
                cur = cur.Left
            }
            cur = root
            // 此时 root 已经在[low, high] 范围内,处理右孩子大于 high 的情况
            for cur != nil {
                for cur.Right != nil && cur.Right.Val > high {
                    cur.Right = cur.Right.Left
                }
                cur = cur.Right
            }
            return root
        }
    
  • 108有序数组转二叉搜索树

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

  • 因为是有序数组,所以可以很方便的找到中间结点。然后向下构建树即可。
  • 讲解观后感

  • 递归操作中利用双指针获得中间结点是很巧妙的方法。需要注意循环不变量原则,选择左闭右开还是左闭右闭要记得边界的调整
  • 利用golang切片的特性,可以得到更简洁的代码。
  • 解题代码

  • 双指针递归
  •     func sortedArrayToBST(nums []int) *TreeNode {
        
            root := linkNode(nums, 0, len(nums)-1)
            return root
        }
        
        func linkNode(nums []int, left int, right int) *TreeNode {
            if left>right {
                return nil
            } 
        
            nodeIdx := left + (right - left)/2
            node := &TreeNode{Val:nums[nodeIdx]}
        
            node.Left = linkNode(nums, left, nodeIdx-1)
            node.Right = linkNode(nums, nodeIdx+1, right)
        
            return node
        }
    
  • 切片递归
  •     func sortedArrayToBST(nums []int) *TreeNode {
            if len(nums) == 0 {    //终止条件,最后数组为空则可以返回
                return nil
            }
            idx := len(nums)/2
            root := &TreeNode{Val: nums[idx]} 
             
            root.Left = sortedArrayToBST(nums[:idx])
            root.Right = sortedArrayToBST(nums[idx+1:])
        
            return root
        }
    
  • 538二叉搜索树转累加树

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

  • 想法是可以利用中序遍历先得到有序数组,然后通过倒序累加的方式得到累加和的新数组。因为原节点值各不相同,可以利用两个数组构建map。然后通过遍历修改节点数值。
  • 讲解观后感

  • 直接利用右中左的遍历顺序就可以一次完成求得的和值和遍历结点的过程。只需要一个变量存储和值即可。
  • 解题代码

  •     var pre int
        func convertBST(root *TreeNode) *TreeNode {
            pre = 0
            traversal(root)
            return root
        }
        
        func traversal(cur *TreeNode) {
            if cur == nil {
                return
            }
            traversal(cur.Right)
            cur.Val += pre
            pre = cur.Val
            traversal(cur.Left)
        }