算法 - 二叉树04(Swift版本)

71 阅读3分钟

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

讲解  
leetcode

层序遍历依旧顺手

// 层序遍历
class Solution {
    func findBottomLeftValue(_ root: TreeNode?) -> Int {
        var queue = [root]
        var left: TreeNode?
        while !queue.isEmpty {
            let size = queue.count
            left = queue[0]
            for _ in 0..<size {
                let node = queue.removeFirst()
                if let left = node?.left {  queue.append(left) }
                if let right = node?.right {  queue.append(right) }
            }
        }
        return left?.val ?? 0
    }
}

// 递归
class Solution {
    var bottomLeftVal = 0
    var maxDepth = -1
    func findBottomLeftValue(_ root: TreeNode?) -> Int {
        recursive(root, depth: 0)
        return bottomLeftVal
    }

    func recursive(_ root: TreeNode?, depth: Int) {
        if root?.left == nil, root?.right == nil {
            if depth > maxDepth {
                maxDepth = depth
                bottomLeftVal = root?.val ?? 0
            }
        }
        if let left = root?.left {
            recursive(left, depth: depth + 1)
        }
        if let right = root?.right {
            recursive(right, depth: depth + 1)
        }
    }
}

题目2: 112. 路径总和

讲解  
leetcode

最初想法 直接用路径集合的模版代码,判断一下是否有符合条件的路径即可。
细化想想整个迭代过程 联系一下递归的思路。
粗看了下题解。

返回值 为bool值: 递归定义为 给一个根节点 和 目标值target, 返回是否有路径(根节点到叶子节点)之和等于target的结果。

递归终止条件: 判断 如果是叶子节点, 则返回 target == 0 。 等于0说明路径之和减到0了。

递归逻辑:
如果左节点有值, 那么调用递归,入参根节点为: 左节点,入参target为: target - 左节点.val(回溯逻辑)。
右边节点处理逻辑同上。

返回值: 左右节点的结果 取或。

按照上述思路写完,基本正确,唯一需要修改的点是, 缺少了 减根节点的值 操作。 补上之后如下。

class Solution {
    func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
        guard let root else { return false }
        return recursivelySum(root, targetSum - root.val)
    }

    func recursivelySum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
        print("\(targetSum) \(root?.val ?? 0) \(root?.left?.val)")
        if root?.left == nil, root?.right == nil {
            return targetSum == 0
        }
        var leftRes = false
        var rightRes = false
        if let left = root?.left {
            leftRes = recursivelySum(left, targetSum - left.val)
        }
        if let right = root?.right {
            rightRes = recursivelySum(right, targetSum - right.val)
        }
        return leftRes || rightRes
    }
}

// 精简版本 真是漂亮
class Solution {
    func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
        guard let root else { return false}
        if root.left == nil, root.right == nil { return targetSum == root.val }
        return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val)
    }
}

刷了路径总和2

class Solution {
    var res = [[Int]]()
    func pathSum(_ root: TreeNode?, _ targetSum: Int) -> [[Int]] {
        guard let root else { return res }        
        pathRecursive(root, targetSum - root.val, path: [root.val])
        return res
    }

    func pathRecursive(_ root: TreeNode?, _ targetSum: Int, path: [Int]) {
        if root?.left == nil, root?.right == nil, targetSum == 0 {
            res.append(path)
        }
        
        if let left = root?.left {
            pathRecursive(left, targetSum - left.val, path: path + [left.val])
        }
        if let right = root?.right {
            pathRecursive(right, targetSum - right.val, path: path + [right.val])
        }
    }
}

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

讲解
leetcode

构造递归
返回值: 返回二叉树根节点
参数列表:中序遍历 和 后序遍历的数组 + 中序切割坐标(起始index + 重点index) + 后序切割坐标(起始index + 重点index)

初始化node,val设置为后序数组最后一个元素。

递归终止:
切割后的数组元素个数 小于等于1

递归体:
以后序数组最后一个元素切割 中序数组
再以中序数组切割后的元素个数相等的性质 切割后序数组

node.left = 递归(入参是 切割后的中序数组左侧 + 切割后的后序数组左侧)
node.right = 递归(入参是 切割后的中序数组右侧 + 切割后的后序数组右侧)
return node

比预期多的修改是要增加下面的判断
if inEnd < inBegin || postEnd < postBegin { return nil }
case是 [2, 1] 会越界

class Solution {
    func buildTree(_ inorder: [Int], _ postorder: [Int]) -> TreeNode? {
        buildTreeRecursive(inorder, postorder, 0, inorder.count - 1, 0, postorder.count - 1)
    }

    func buildTreeRecursive(_ inorder: [Int], _ postorder: [Int], _ inBegin: Int, _ inEnd: Int, _ postBegin: Int, _ postEnd: Int) -> TreeNode? {
        if inEnd < inBegin || postEnd < postBegin { return nil }
        print(" \(inBegin) \(inEnd) \(postBegin) \(postEnd)")
        let rootVal = postorder[postEnd]
        let node = TreeNode(rootVal)
        if inEnd - inBegin == 0 { return node }
        // 切分中序 
        let mid = Int(inorder.firstIndex(of: rootVal) ?? 0)
        let leftLength = mid - inBegin 
        node.left = buildTreeRecursive(inorder, postorder, inBegin, mid - 1, postBegin, postBegin + leftLength - 1)
        node.right = buildTreeRecursive(inorder, postorder, mid + 1, inEnd, postBegin + leftLength, postEnd - 1)
        return node
    }
}