算法通关村——原来如此简单

2.白银挑战——二叉树的层次遍历经典问题

2.基本的层次遍历与变换

2.1 二叉树的层序遍历

LeetCode102:给你一个二叉树,请你返回其按层序遍历得到的节点值。(即逐层地,从左到右访问所有节点)。

按层打印经典代码:

class Node:
    def __init__(self, val=-1, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Tree:
    def __init__(self, root=None):
        self.root = root

    def init_tree(self):
        node_9 = Node(9)
        node_15 = Node(15)
        node_7 = Node(7)
        node_20 = Node(20, node_15, node_7)
        root = Node(3, node_9, node_20)
        return root

class LevelOrder:
    def basic_level_order(self, root):
        if not root:
            return []
        res = []
        queue = [root]
        while queue:
            size = len(queue)
            tmp = []
            # 将队列中元素都拿出来,放在临时List中
            for _ in range(size):
                r = queue.pop(0)
                tmp.append(r.val)
                if r.left:
                    queue.append(r.left)
                if r.right:
                    queue.append(r.right)
            res.append(tmp)
        return res

if __name__ == "__main__":
    tree = Tree()
    root = tree.init_tree()
    levelOrder = LevelOrder()
    res = levelOrder.basic_level_order(root)
    print(res)

2.2 层次遍历——自底向上

思路:在遍历完一层节点之后,将存储该层节点值的列表添加到结果列表的头部

import collections

class Node:
    def __init__(self, val=-1, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Tree:
    def __init__(self, root=None):
        self.root = root

    def init_tree(self):
        node_9 = Node(9)
        node_15 = Node(15)
        node_7 = Node(7)
        node_20 = Node(20, node_15, node_7)
        root = Node(3, node_9, node_20)
        return root

class LevelOrderBottom:
    def levelOrderBottom(self, root):
        levelOrder = list()
        if not root:
            return levelOrder
        q = collections.deque([root])
        while q:
            level = list()
            size = len(q)
            for _ in range(size):
                node = q.popleft()
                level.append(node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            levelOrder.append(level)

        return levelOrder[::-1]

if __name__ == "__main__":
    tree = Tree()
    root = tree.init_tree()
    levelOrder = LevelOrderBottom()
    res = levelOrder.levelOrderBottom(root)
    print(res)

deque() (双向队列)

deque是栈和队列的一种广义实现,deque是"double-end queue"的简称;deque支持线程安全、有效内存地以近似O(1)的性能在deque的两端插入和删除元素,尽管list也支持相似的操作,但是它主要在固定长度操作上的优化,从而在pop(0)和insert(0,v)(会改变数据的位置和大小)上有O(n)的时间复杂度。

常用方法:

append():从右端添加元素,

appendleft():从左端添加元素,

extend():从右端逐个添加可迭代对象,

python中的可迭代对象有:列表,元组,字典,字符串,

extendleft():从左端逐个添加可迭代对象,

pop():移除列表中的一个元素(默认最右端的一个元素)并返回该元素的值,如果没有元素,将会报出IndexError

popleft():移除列表中的一个元素(默认最左端的一个元素),并且返回该元素的值,如果没有元素,将会报出IndexError

count():统计队列中的元素个数

insert(index,obj):在指定位置插入元素

rotate(n):rotate(n), 从右侧反转n步,如果n为负数,则从左侧反转。d.rotate(1) 等于 d.appendleft(d.pop())

clear():将deque中的元素全部删除,最后长度为0

remove():移除第一次出现的元素,如果没有找到,报出ValueError

maxlen:只读的属性,deque限定的最大长度,如果无,就返回None。当限制长度的deque增加超过限制数的项时, 另一边的项会自动删除

2.3二叉树的锯齿形层序遍历

LeetCode103:给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

如果是从左至右,我们每次将被遍历到的元素插入至双端队列的末尾

从右至左,我们每次将被遍历到的元素插入至双端队列的头部。

import collections


class Node:
    def __init__(self, val=-1, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Tree:
    def __init__(self, root=None):
        self.root = root
    def init_tree(self):
        node_9 = Node(9)
        node_15 = Node(15)
        node_7 = Node(7)
        node_20 = Node(20, node_15, node_7)
        root = Node(3, node_9, node_20)
        return root

class ZigzagLevelOrder:
    def zigzagLevelOrder(self, root):
        if not root:
            return []
        res = []
        q = collections.deque() #q为一个双端可插入的序列
        q.append(root)
        while q:
            res_tmp = []
            n = len(q)
            for i in range(n):
                tmp = q.popleft()
                res_tmp.append(tmp.val)
                if tmp.left:
                    q.append(tmp.left)
                if tmp.right:
                    q.append(tmp.right)
            res.append(res_tmp)
        for j in range(len(res)):
            if j % 2 == 1:
                res[j].reverse()
        return res  # return的位置

if __name__ == '__main__':
    tree = Tree()
    root = tree.init_tree()
    zigzag = ZigzagLevelOrder()
    res = zigzag.zigzagLevelOrder(root)
    print(res)

2.4 N叉树的层序遍历

LeetCode429:给定一个N叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)

树的序列化输入是用层序遍历,每组节点都有null值分隔

class NLevelOrder:
    def nlevelOrder(self, root: 'Node'):
        if not root:
            return []
        ans = list()
        q = deque([root])
        while q:
            n = len(q)
            level = list()
            for _ in range(n):
                cur = q.popleft()
                level.append(cur.val)
                for child in range(len(level)):
                    q.append(child)
            ans.append(level)

        return ans

3.几个处理每层元素的题目

3.1在每个树行中找最大值

LeetCode515:给定一颗二叉树的根节点root,请找出该二叉树中每一层的最大值

在得到一层之后使用一个变量来记录当前得到的最大值:

class Node:
    def __init__(self, val=-1, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Tree:
    def __init__(self, root=None):
        self.root = root

    def init_tree(self):
        node_5 = Node(5)
        node_3 = Node(3)
        node_9 = Node(9)
        node_3 = Node(3, node_5, node_3)
        node_2 = Node(2, None, node_9)
        root = Node(1, node_3, node_2)
        return root

class LargestValues:
    def largestValues(self, root):
        if not root:
            return []
        ans = []
        q = [root]
        while q:
            maxVal = -1
            tmp = q
            q = []
            for node in tmp:
                maxVal = max(maxVal, node.val)
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            ans.append(maxVal)
        return ans


if __name__ == "__main__":
    tree = Tree()
    root = tree.init_tree()
    largestValues = LargestValues()
    res = largestValues.largestValues(root)
    print(res)

3.2 在每个树行中找平均值

LeetCode 637:要求给定一个非空二叉树,返回一个由每层节点平均值组成的数组

import collections


class Node:
    def __init__(self, val=-1, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Tree:
    def __init__(self, root=None):
        self.root = root

    def init_tree(self):
        node_9 = Node(9)
        node_15 = Node(15)
        node_7 = Node(7)
        node_20 = Node(20, node_15, node_7)
        root = Node(3, node_9, node_20)
        return root

class AverageOfLevels:
    def averageOfLevels(self, root):
        if not root:
            return []
        q = collections.deque()
        q.append(root)
        res = []
        while q:
            n = len(q)
            sum = 0
            for _ in range(n):
                node = q.popleft()
                sum += node.val
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
            res.append(sum/n)
		return res

if __name__ == "__main__":
    tree = Tree()
    root = tree.init_tree()
    averageOfLevels = AverageOfLevels()
    res = averageOfLevels.averageOfLevels(root)
    print(res)

3.3 二叉树的右视图

LeetCode 199:给定一个二叉树的根节点root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧能看到的节点值。

3.4 最底层最左边

正常执行层次遍历,不管最底层由几个元素,最后一个输出的一定是最底层最右的元素,每一层都是先反转再放入队列,就可以让最后一个输出的是最左的。

nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量

class Node:
    def __init__(self, val=-1, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Tree:
    def __init__(self, root=None):
        self.root = root

    def init_tree(self):
        node_9 = Node(9)
        node_15 = Node(15)
        node_7 = Node(7)
        node_20 = Node(20, node_15, node_7)
        root = Node(3, node_9, node_20)
        return root

class FindBottomLeftValue:
    def findBottomLeftValue(self, root):
        curVal = curHeight = 0
        def dfs(node, height):
            if node is None:
                return
            height += 1
            dfs(node.right, height)
            dfs(node.left, height)
            # 注意right和left的上下位置和下边判定条件的关系
            nonlocal curVal, curHeight
            if height > curHeight:
                curHeight = height
                curVal = node.val
        dfs(root, 0)
        return curVal

if __name__ == "__main__":
    tree = Tree()
    root = tree.init_tree()
    findBottomLeftValue = FindBottomLeftValue()
    res = findBottomLeftValue.findBottomLeftValue(root)
    print(res)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值