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

题目介绍

描述:

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

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

    3
   / \\
  9  20
    /  \\
   15   7
返回其层次遍历结果:

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

提示:

节点总数 <= 1000

解题思路:

递归算法的关键是要明确函数的「定义」是什么,然后相信这个定义,利用这个定义推导最终结果。

写树相关的算法,简单说就是,先搞清楚当前 root 节点该做什么,然后根据函数定义递归调用子节点,递归调用会让孩子节点做相同的事情。

二叉树题目的一个难点在于如何通过题目的要求思考出每一个节点需要做什么

二叉树解题策略

一 递归 二 队列 + 迭代 (层次遍历) 三 栈 + 迭代 (非递归遍历) 四 其它

三种基本的遍历方式,都可以用递归来实现。写递归算法的时候,需要注意递归退出条件以及递归操作的表达。

自己的解法实现

def levelOrder4(self, root):
        if not root: return []
        res, stack = [], [root]
        while stack:
            tmp = []
            for _ in range(len(stack)):
                node = stack.pop(0)
                tmp.append(node.val)
                if node.left: stack.append(node.left)
                if node.right: stack.append(node.right)
            res.append(tmp[::-1] if len(res) % 2 else tmp)
        return res

网上比较优秀的解法

解法一

方法一:层序遍历 + 双端队列 利用双端队列的两端皆可添加元素的特性,设打印列表(双端队列) tmp ,并规定: 奇数层 则添加至 tmp 尾部 , 偶数层 则添加至 tmp 头部 。

算法流程:

  1. 特例处理: 当树的根节点为空,则直接返回空列表 [] ;
  2. 初始化: 打印结果空列表 res ,包含根节点的双端队列 deque ;
  3. BFS 循环: 当 deque 为空时跳出; 4新建列表 tmp ,用于临时存储当前层打印结果; 当前层打印循环: 循环次数为当前层节点数(即 deque 长度); 出队: 队首元素出队,记为 node; 打印: 若为奇数层,将 node.val 添加至 tmp 尾部;否则,添加至 tmp 头部; 添加子节点: 若 node 的左(右)子节点不为空,则加入 deque ; 将当前层结果 tmp 转化为 list 并添加入 res ; 返回值: 返回打印结果列表 res 即可;
def levelOrder(self, root):
        from collections import deque
        if not root: return []
        res, queue = [], deque([root])
        while queue:
            tmp = deque()
            for _ in range(len(queue)):
                node = queue.popleft()
                if len(res) % 2:
                    tmp.appendleft(node.val)  # 偶数层 -> 队列头部
                else:
                    tmp.append(node.val)  # 奇数层 -> 队列尾部
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(list(tmp))
        return res

解法二

方法二:层序遍历 + 双端队列(奇偶层逻辑分离) 方法一代码简短、容易实现;但需要判断每个节点的所在层奇偶性,即冗余了 NN 次判断。 通过将奇偶层逻辑拆分,可以消除冗余的判断。 算法流程: 与方法一对比,仅 BFS 循环不同。

BFS 循环: 循环打印奇 / 偶数层,当 deque 为空时跳出; 打印奇数层: 从左向右 打印,先左后右 加入下层节点; 若 deque 为空,说明向下无偶数层,则跳出; 打印偶数层: 从右向左 打印,先右后左 加入下层节点;

def levelOrder2(self, root):
        from collections import deque
        if not root: return []
        res, queue = [], deque()
        queue.append(root)
        while queue:
            tmp = []
            # 打印奇数层
            for _ in range(len(queue)):
                # 从左向右打印
                node = queue.popleft()
                tmp.append(node.val)
                # 先左后右加入下层节点
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            res.append(tmp)
            if not queue: break    # 若为空则提前跳出
            # 打印偶数层
            tmp = []
            for _ in range(len(queue)):
                # 从右向左打印
                node = queue.pop()
                tmp.append(node.val)
                # 先右后左加入下层节点
                if node.right:queue.appendleft(node.right)
                if node.left: queue.appendleft(node.left)
            res.append(tmp)
        return res

解法三

方法三:层序遍历 + 倒序 此方法的优点是只用列表即可,无需其他数据结构。 偶数层倒序: 若 res 的长度为 奇数 ,说明当前是偶数层,则对 tmp 执行 倒序 操作。

def levelOrder3(self, root):
        from collections import deque
        res, queue = [], deque([root])

        while queue:
            tmp = []
            for _ in range(len(queue)):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            res.append(tmp[::-1] if len(res)%2 else tmp)
        return res

相关知识总结和思考

相关知识:

BFS:广度/宽度优先。其实就是从上到下,先把每一层遍历完之后再遍历一下一层。

可以使用Queue的数据结构。我们将root节点初始化进队列,通过消耗尾部,插入头部的方式来完成BFS。

二叉搜索树(BST)的特性:

  1. 若它的左子树不为空,则所有左子树上的值均小于其根节点的值
  2. 若它的右子树不为空,则所有右子树上的值均大于其根节点的值
  3. 它的左右子树也分别为二叉搜索树

递归与迭代的区别

递归:重复调用函数自身实现循环称为递归; 迭代:利用变量的原值推出新值称为迭代,或者说迭代是函数内某段代码实现循环;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341