题目1: 513.找树左下角的值
层序遍历依旧顺手
// 层序遍历
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. 路径总和
最初想法 直接用路径集合的模版代码,判断一下是否有符合条件的路径即可。
细化想想整个迭代过程 联系一下递归的思路。
粗看了下题解。
返回值 为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.从中序与后序遍历序列构造二叉树
构造递归
返回值: 返回二叉树根节点
参数列表:中序遍历 和 后序遍历的数组 + 中序切割坐标(起始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
}
}