LeetCode 987.二叉树的垂序遍历 python/scala

环境:python 3.6,scala 2.11.8

题意

二叉树的垂序遍历:

  • 假设某节点坐标为(x, y),则其左右子节点坐标为(x-1, y-1)(x+1, y-1)
  • 返回二维列表,x坐标相同的节点会被添加至同一个子列表;
  • 坐标x、y完全相同的节点,优先添加较小值;
  • 二维列表中子列表之间的顺序是以x升序返回;
  • 树的节点数范围 [1, 1000],节点值范围[0, 1000]

分析

  • 注意:至少掌握二叉树的前中后三种遍历方式的其中一种;
  • 思路:遍历二叉树,将节点值及其坐标添加至集合。再按坐标排序得到最终结果;
  • 方法:
    • 由题意可知,中序遍历方式更合适;
    • 遍历方法可选择递归或迭代;
    • 常见的用列表装载节点值及其坐标,Python 中也可使用 collections.defaultdict(list)
    • 排序方式为按x升序、y降序、节点值升序;便于编程,这里也可以假设节点坐标为(x, y)的左右子节点坐标为(x-1, y+1)(x+1, y+1),这样都能默认以升序排序。具体排序细节根据集合的选用而异;
  • 题中给定的节点数和节点值条件,详见代码细节;

代码

python

import collections


# 中序遍历,按垂线树深双属性顺序加载
def verticalTraversal(root):
    """
    :type root: TreeNode
    :rtype: List[List[int]]
    """
    if not root: return []
    rs = []

    def dfs(node, x, y):
        if node:
            dfs(node.left, x - 1, y + 1)
            rs.append((x, y, node.val))
            dfs(node.right, x + 1, y + 1)

    dfs(root, 0, 0)
    # 若这里装载元素为(val, x, y),则用 python 多属性排序会超时
    rs.sort()
    res = []

    minimum = -1001 # 极限情况下节点值不会小于 -1000
    for x, y, val in rs:
        if x != minimum:
            res.append([])
            minimum = x
        res[-1].append(val)
    return res


# 中序遍历,同一垂线按树深顺序加载
def verticalTraversalV2(root):
    if not root: return []
    d = collections.defaultdict(list)

    def dfs(node, x, depth):
        if node:
            dfs(node.left, x - 1, depth + 1)
            d[x].append((depth, node.val))
            dfs(node.right, x + 1, depth + 1)

    dfs(root, 0, 0)
    res = []
    for key in sorted(d.keys()):
        d[key].sort()
        res.append([e[1] for e in d[key]])
    return res


# 同上
def verticalTraversalV3(root):
    """
    :param root:
    :return:
    """
    if not root: return []

    stack = [(root, 0, 0)] # 节点,x坐标, 深度
    d = collections.defaultdict(list)

    while stack:
        children = []
        for node, x, depth in stack:
            if node:
                d[x].append((depth, node.val))
                children.append((node.left, x - 1, depth + 1))
                children.append((node.right, x + 1, depth + 1))
        stack = children

    res = []
    for key in sorted(d.keys()):
        d[key].sort()
        res.append([e[1] for e in d[key]])
    return res

scala

import scala.collection.mutable.ListBuffer

object LC987 {
  /** 这里提交后超时了,可参考第二种写法*/ 
  def verticalTraversal(root: TreeNode): List[List[Int]] = {
    val rs = ListBuffer.empty[(Int, Int, Int)]

    def dfs(node: TreeNode, x: Int, y: Int): Unit = {
      if (node != null) {
        dfs(node.left, x - 1, y + 1)
        rs.append((x, y, node.value))
        dfs(node.right, x + 1, y + 1)
      }
    }

    dfs(root, 0, 0)

    val res = ListBuffer.empty[ListBuffer[Int]]
    var minimum = -1001

    for ((x, _, value) <- rs.sortBy(e => (e._1, e._2))) {
      if (x != minimum) {
        res.append(ListBuffer.empty[Int])
        minimum = x
      }
      res.last.append(value)
    }
    res.map(_.toList).toList
  }

  case class Node(x: Int, depth: Int, value: Int)

  def verticalTraversalV2(root: TreeNode): List[List[Int]] = {
    def dfs(node: TreeNode, x: Int, depth: Int): List[Node] =
      if (node == null) List.empty[Node]
      else dfs(node.left, x - 1, depth + 1) ::: List(Node(x, depth, node.value)) ::: dfs(node.right, x + 1, depth + 1)

    val nodes = dfs(root, 0, 0)

    nodes.groupBy(_.x).toList sortBy(_._1) map { case (_, nod) =>
      nod.sortBy(neighbor => (neighbor.depth, neighbor.value)).map(_.value)}
  }
}

最后

欢迎交流和补充

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

推荐阅读更多精彩内容