《剑指Offer》阅读笔记(swift):二叉树(12题)、二叉树搜索树(3题)

386 阅读3分钟

我的Github地址

小码哥《恋上数据结构与算法》笔记

极客时间《iOS开发高手课》笔记

iOS大厂面试高频算法题总结

iOS面试资料汇总

  • 二叉树(12道):
    • 剑指Offer(07):重建二叉树
    • 剑指Offer(26):树的子结构
    • 剑指Offer(27):二叉树的镜像
    • 剑指Offer(28):对称的二叉树
    • 剑指Offer(32):从上往下打印二叉树
    • 剑指Offer(32):分行从上到下打印二叉树
    • 剑指Offer(32):之字形打印二叉树
    • 剑指Offer(34):二叉树中和为某一值的路径
    • 剑指Offer(37):序列化二叉树
    • 剑指Offer(55):二叉树的深度
    • 剑指Offer(55):平衡二叉树
    • 剑指Offer(五十七):二叉树的下一个结点(未找到该题目)
  • 二叉搜索树(3道):
    • 剑指Offer(33):二叉搜索树的后序遍历序列
    • 剑指Offer(36):二叉搜索树与双向链表
    • 剑指Offer(54):二叉搜索树的第k大节点

面试题7:重建二叉树

题目一

思路一

代码

class Solution {
    func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? {
        if preorder.count == 0 || inorder.count == 0 {
            return nil
        }
        
        //构建二叉树根结点
        let root: TreeNode? = TreeNode.init(preorder[0])
        
        //对中序序列进行遍历
        for (index, num) in inorder.enumerated() {
            // 如果找到根节点
            if num == preorder[0] {
                root?.left = buildTree(
                                Array(preorder[1..<index+1]),
                                Array(inorder[0..<index])
                            )
                root?.right = buildTree(
                                Array(preorder[index+1..<preorder.endIndex]), 
                                Array(inorder[index+1..<inorder.endIndex])
                            )
            }
        }
        
        return root
        
    }
}

面试题26:树的子结构

题目一

思路一

代码

class Solution {
    func isSubStructure(_ A: TreeNode?, _ B: TreeNode?) -> Bool {
        if A == nil || B == nil {
            return false   
        }

        return  dfs(A,B) || isSubStructure(A?.left,B) || isSubStructure(A?.right, B)

    }

    func dfs(_ A: TreeNode?, _ B: TreeNode?) -> Bool {
        if B == nil {
            return true
        }
        if A == nil || A!.val != B!.val {
            return false
        }

        return dfs(A?.left, B?.left) && dfs(A?.right, B?.right)

    }
}

面试题27:二叉树的镜像

## 题目一

思路一

代码

func mirrorTree(_ root: TreeNode?) -> TreeNode? {
    guard let root = root else { return nil }
    let right = mirrorTree(root.right)
    let left = mirrorTree(root.left)
    root.right = left
    root.left = right
    return root
}

func mirrorTree2(_ root: TreeNode?) -> TreeNode? {
    guard root != nil else {
        return nil
    }
    var queue = [TreeNode]()
    queue.append(root!)
    while !queue.isEmpty {
        let node = queue.removeFirst()
        let nodeLeft = node.left
        node.left = node.right
        node.right = nodeLeft
        if node.left != nil {
            queue.append(node.left!)
        }
        if node.right != nil {
            queue.append(node.right!)
        }
    }
    return root
}

面试题28:对称的二叉树

题目一

思路一

代码

func isSymmetric(_ root: TreeNode?) -> Bool {
    guard let root = root else { return true }
    return dfs(left: root.left, right: root.right)
}

func dfs(left: TreeNode?, right: TreeNode?) -> Bool {
    if left == nil && right == nil {
        return true
    }
    
    if left == nil || right == nil {
        return false
    }
    
    if left!.val != right!.val {
        return false
    }
    
    return dfs(left: left!.left, right: right!.right) && dfs(left: left!.right, right: right!.left)
}

面试题32:从上往下打印二叉树

题目一

思路一

代码

class Solution {
    func levelOrder(_ root: TreeNode?) -> [Int] {
        var stack = [Int]()
        if let root = root {
            var nodes = [root]
            var idx = 0
            while idx < nodes.count {
                let node = nodes[idx]
                stack.append(node.val)
                if let left = node.left {
                    nodes.append(left)
                }
                if let right = node.right {
                    nodes.append(right)
                }
                idx += 1
            }
        }
        return stack
    }
} 

题目二:分行从上到下打印二叉树

代码

func levelOrder(_ root: TreeNode?) -> [[Int]] {
    guard let root = root else { return [] }
    
    var result = [[Int]]()
    var queue: [TreeNode] = [root]
    
    while !queue.isEmpty {
        var current = [Int]()
        
        for _ in 0 ..< queue.count {
            let node = queue.removeFirst()
            current.append(node.val)
            
            if node.left != nil {
                queue.append(node.left!)
            }
            
            if node.right != nil {
                queue.append(node.right!)
            }
        }
        result.append(current)
    }
    return result
}

题目三:之字形打印二叉树

思路一

代码

func zigzagLevelOrder(_ root: TreeNode?) -> [[Int]] {
    
    //1. 空判断
    guard let root = root else { return [[Int]]() }
    
    var result = [[Int]]()
    var queue = [root]
    var isZ = false
    
    //2. 创建队列,加入root
    while !queue.isEmpty {
        var cur = [Int]()
        //3. 遍历一次队列
        for _ in 0..<queue.count {
            let node = queue.removeFirst()
            //4. 将队列的值保存
            cur.append(node.val)
            //5. 队列中添加新值
            if node.left != nil {queue.append(node.left!)}
            if node.right != nil {queue.append(node.right!)}
        }
        if isZ { cur.reverse() }
        result.append(cur)
        isZ = !isZ
    }
    return result
}

面试题34:二叉树中和为某一值的路径

题目一

思路一

代码

var path = [Int]()
var res = [[Int]]()

func pathSum(_ root: TreeNode?, _ sum: Int) -> [[Int]] {
    
    dfs(root, sum)
    return res
}

func dfs(_ root: TreeNode?, _ sum: Int) {
    guard let root = root else { return }
    
    path.append(root.val)
    let tmp = sum - root.val
    if tmp == 0 && root.left == nil && root.right == nil {
        res.append(path)
    }
    
    dfs(root.left, tmp)
    dfs(root.right, tmp)
    
    path.removeLast() // 重点,遍历完后,需要把当前节点remove出去,因为用的是同一个list对象来存所有的路径
}

面试题37:序列化二叉树

题目一

面试题55:二叉树的深度

题目一

思路一

代码

func maxDepth(_ root: TreeNode?) -> Int {
    guard let root = root else { return 0 }
    
    let leftDepth = maxDepth(root.left)
    let rightDepth = maxDepth(root.right)
    
    return max(leftDepth, rightDepth) + 1
}

题目二:平衡二叉树

思路一

代码

class Solution {
     //! 是否是平衡树
  func isBalanced(_ root: TreeNode?) -> Bool {
    if root == nil {
      return true
    }
    return help(root) >= 0
  }
  
  func help(_ root:TreeNode?) ->Int {
    if root==nil {
      return 0
    }
    
    let leftHeight = help(root?.left)
    let rightHeight = help(root?.right)
    //! 提前退出
    if leftHeight == -1 || rightHeight == -1 || abs(leftHeight-rightHeight) > 1 {
      return -1
    } else {
      return max(leftHeight, rightHeight)+1
    }
  }
}

面试题33:二叉搜索树的后序遍历序列

题目一

思路一

代码

class Solution {
    func verifyPostorder(_ postorder: [Int]) -> Bool {
        return recur(postorder)
    }
    
    func recur(_ postorder: [Int]) -> Bool {
        if postorder.count == 1 || postorder.count == 0 { //这里,当只有一个节点或者无节点,认为是。
            return true
        }
        var i = 0
        let length = postorder.count
        let root = postorder.last!
        for num in postorder[0..<length - 1] { //注意剔除最后一个元素,即根节点。
            if num > root {
                break
            }
            i += 1
        }
        if i < length - 1 {
            for num in postorder[i..<length - 1] { //查看右半部分节点是否满足条件。
                if num < root {
                    return false
                }
            }
        }
        
        var left = true
        if i > 0 {
            left = self.recur(Array(postorder[0..<i])) //递归左边的子树,看看是否满足条件。
        }
        
        var right = true
        if i < length - 1 {
            right = verifyPostorder(Array(postorder[i..<length - 1])) //递归右边的子树,看是否满足条件。
        }
        
        return left && right
    }
}

面试题36:二叉搜索树与双向链表

题目一

思路一

面试题54:二叉搜索树的第k大节点

题目一

思路一

代码

class Solution {
    func kthLargest(_ root: TreeNode?, _ k: Int) -> Int {
        
        var stack = [TreeNode?]()   //模拟栈,临时存储待探索的节点
        var curr: TreeNode? = root  //指向树根
        var nodeVals = [Int]()  //存储各个节点的值
        
        //中序遍历二叉树
        while curr != nil || !stack.isEmpty {
            
            while curr != nil {
                
                stack.append(curr)
                curr = curr?.left
            }
            
            curr = stack.removeLast()
            nodeVals.append(curr!.val)  //将每个节点值加入到数组中。因为是二叉搜索树,所以中序遍历的结果是递增的结果
            curr = curr?.right
        }
        
        return nodeVals[nodeVals.count - k]
    }
}