[剑指Offer]32~35

[剑指Offer]32~35

学习使用工具

剑指Offer http://itmyhome.com/sword-means-offer/sword-means-offer.pdf

LeetCode的剑指Offer题库 https://leetcode.cn/problemset/all/

剑指 Offer 32 - III. 从上到下打印二叉树 III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [20,9],
  [15,7]
]

提示:

节点总数 <= 1000

解法:

在32-II题的基础上再增加一个层计数level。当level为奇数时,正常将lres加入res;当level为偶数时,将lres的倒序加入res。

def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        
        queue = collections.deque()
        res = []
        lres = []
        num = 1
        temp = num
        flag = 0
        level = 1

        queue.append(root)
        while queue:
            node = queue.popleft()
            lres.append(node.val)
            if node.left:
                queue.append(node.left)
            else: flag += 1
            if node.right:
                queue.append(node.right)
            else: flag += 1
            
            temp -= 1
            if temp <= 0 :
                if level % 2 == 0:
                    res.append(lres[::-1])
                else:
                    res.append(lres)
                lres = []
                num *= 2
                num -= flag
                temp = num
                flag = 0
                level += 1

        return res

正常的做法:这道题的思想就是奇数行正常遍历,偶数行进行从右到左遍历。设置一个标志位level判断当前行是奇数行还是偶数行,如果是奇数行,那下一行就是偶数行,我们可以将当前节点的子节点从左到右入栈,然后出栈的时候赋给队列就是从右到左;同理当前行如果是偶数行,说明下一行就是奇数行,那我们将子节点入栈的时候从右到左,出栈时候的顺序就是从左到右。

剑指 Offer 33. 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

参考以下这颗二叉搜索树:

     5
    / \
   2   6
  / \
 1   3

示例 1:

输入: [1,6,3,2,5]
输出: false

示例 2:

输入: [1,3,2,6,5]
输出: true

提示:

数组长度 <= 1000

解法:

如果某个数组为一个二叉树的后序遍历,那么它满足以下条件:

  • 数组最后一个元素为二叉树的根节点;数组前半部分的元素都比根节点小,为左子树;数组后半部分(除了根节点本身)的元素都比根节点大,为右子树
  • 左子树和右子树也满足上一条性质

根据以上性质,二分+递归判断即可。

def verifyPostorder(self, postorder: List[int]) -> bool:
        if not postorder:
            return True

        def check(postorder: List[int]):
            length = len(postorder)
            if length <= 2:
                return True
            key = postorder[-1]

            i = -1
            while(postorder[i + 1] < key):
                i += 1
                
            if postorder[i + 1: length - 1] and min(postorder[i + 1: length - 1]) < key:
                return False
            
            return check(postorder[0 : i]) and check(postorder[i + 1: length - 1])
            
        return check(postorder)

剑指 Offer 34. 二叉树中和为某一值的路径

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:

img

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:

img

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

提示:

  • 树中节点总数在范围 [0, 5000]
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

解法:

递归遍历+回溯。使用一个temp数组记录满足条件的路径,若满足则加入结果数组。

def pathSum(self, root: TreeNode, target: int) -> List[List[int]]:
        if not root:
            return []

        res = []
        temp = []
        sum = 0
        def travel(root: TreeNode, temp: List[int], sum):
            sum += root.val
            temp.append(root.val)

            if sum == target and not root.left and not root.right:
                res.append(temp[:])

            if root.left:
                travel(root.left, temp, sum)
            if root.right:
                travel(root.right, temp, sum)

            temp.pop()

        travel(root, temp, sum)
        return res

剑指 Offer 35. 复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null

示例 1:

img

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:

img

输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

示例 3:

img

输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]

示例 4:

输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

提示:

  • -10000 <= Node.val <= 10000
  • Node.random 为空(null)或指向链表中的节点。
  • 节点数目不超过 1000 。

解法:

因为Random节点的存在而无法通过仅一遍遍历就复制建立新链表。因此,借助字典,第一次遍历的时候建立无索引的新节点,第二次遍历的时候再建立next和random索引。

def copyRandomList(self, head: 'Node') -> 'Node':
        if not head: return
        dic = {}

        cur = head
        while cur:
            dic[cur] = Node(cur.val)
            cur = cur.next
        cur = head

        while cur:
            dic[cur].next = dic.get(cur.next)
            dic[cur].random = dic.get(cur.random)
            cur = cur.next
            
        return dic[head]
posted @ 2023-03-06 14:27  无机呱子  阅读(15)  评论(0编辑  收藏  举报