leetcode-pp / 91alg-7-daily-check

6 stars 0 forks source link

【Day 18 】2022-04-18 - 987. 二叉树的垂序遍历 #21

Open azl397985856 opened 2 years ago

azl397985856 commented 2 years ago

987. 二叉树的垂序遍历

入选理由

暂无

题目地址

https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree

前置知识

对位于 (X, Y) 的每个结点而言,其左右子结点分别位于 (X-1, Y-1) 和 (X+1, Y-1)。

把一条垂线从 X = -infinity 移动到 X = +infinity ,每当该垂线与结点接触时,我们按从上到下的顺序报告结点的值(Y 坐标递减)。

如果两个结点位置相同,则首先报告的结点值较小。

按 X 坐标顺序返回非空报告的列表。每个报告都有一个结点值列表。

示例 1:

输入:[3,9,20,null,null,15,7] 输出:[[9],[3,15],[20],[7]] 解释: 在不丧失其普遍性的情况下,我们可以假设根结点位于 (0, 0): 然后,值为 9 的结点出现在 (-1, -1); 值为 3 和 15 的两个结点分别出现在 (0, 0) 和 (0, -2); 值为 20 的结点出现在 (1, -1); 值为 7 的结点出现在 (2, -2)。 示例 2:

输入:[1,2,3,4,5,6,7] 输出:[[4],[2],[1,5,6],[3],[7]] 解释: 根据给定的方案,值为 5 和 6 的两个结点出现在同一位置。 然而,在报告 "[1,5,6]" 中,结点值 5 排在前面,因为 5 小于 6。

提示:

树的结点数介于 1 和 1000 之间。 每个结点值介于 0 和 1000 之间。

physicshi commented 2 years ago

思路

这个题的重点在于排序,观察题目可知,坐标反映的是 (depth,order),我们需要对 order 升序,order 一样的(是一组)按 depth 升序,depth 一样的按 node.val 升序

代码

// 坐标是 (depth,order)
var verticalTraversal = function (root) {
  if (!root) return [];
  let queue = [[root, 0, 0]];
  // map缓存的是 order, [[node, depth],[node, depth]]
  let map = new Map();
  let min = Infinity;
  let max = -Infinity;
  let finalArr = [];
  while (queue.length > 0) {
    let first = queue.pop();
    let node = first[0];
    let order = first[2];
    let depth = first[1];
    min = Math.min(order, min);
    max = Math.max(order, max);
    if (map.has(order)) {
      let arr = map.get(order);
      arr.push([node, depth]);
      map.set(order, arr);
    } else {
      map.set(order, [[node, depth]]);
    }
    if (node.left) {
      queue.unshift([node.left, depth + 1, order - 1]);
    }
    if (node.right) {
      queue.unshift([node.right, depth + 1, order + 1]);
    }
  }
  for (let i = min; i <= max; i++) {
    let arr = map.get(i);
    arr.sort((a, b) => {
      // 如果depth相同,就按照 node.val 升序排列
      if (a[1] === b[1]) {
        return a[0].val - b[0].val;
      }
      // 否则就按着 depth 升序排列
      return a[1] - b[1];
    });
    // 我们最后要缓存的只是 node.val
    arr = arr.map((elem) => elem[0].val);
    finalArr.push(arr);
  }
  return finalArr;
};

复杂度

zhulin1110 commented 2 years ago

题目地址(987. 二叉树的垂序遍历)

https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/

题目描述

给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。

对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row + 1, col - 1) 和 (row + 1, col + 1) 。树的根结点位于 (0, 0) 。

二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。

返回二叉树的 垂序遍历 序列。

 

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[9],[3,15],[20],[7]]
解释:
列 -1 :只有结点 9 在此列中。
列  0 :只有结点 3 和 15 在此列中,按从上到下顺序。
列  1 :只有结点 20 在此列中。
列  2 :只有结点 7 在此列中。

示例 2:

输入:root = [1,2,3,4,5,6,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
列 -2 :只有结点 4 在此列中。
列 -1 :只有结点 2 在此列中。
列  0 :结点 1 、5 和 6 都在此列中。
          1 在上面,所以它出现在前面。
          5 和 6 位置都是 (2, 0) ,所以按值从小到大排序,5 在 6 的前面。
列  1 :只有结点 3 在此列中。
列  2 :只有结点 7 在此列中。

示例 3:

输入:root = [1,2,3,4,6,5,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
这个示例实际上与示例 2 完全相同,只是结点 5 和 6 在树中的位置发生了交换。
因为 5 和 6 的位置仍然相同,所以答案保持不变,仍然按值从小到大排序。

 

提示:

树中结点数目总数在范围 [1, 1000] 内
0 <= Node.val <= 1000

思路

DFS + 三元组

代码

JavaScript Code:


/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var verticalTraversal = function(root) {
    const nodeArr = [];

    const getNodeArr = function dfs(root, i, j) {
        if (!root) return;

        nodeArr.push([i, j, root.val]);
        dfs(root.left, i + 1, j - 1);
        dfs(root.right, i + 1, j + 1);
    };

    getNodeArr(root, 0, 0);

    nodeArr.sort((a, b) => {
        if (a[1] !== b[1]) return a[1] - b[1];
        if (a[0] !== b[0]) return a[0] - b[0];
        return a[2] - b[2];
    });

    const resArr = [];
    let lastCol = -1010; // -1000 <= col <= 1000
    for (let i = 0; i < nodeArr.length; ++i) {
        let curCol = nodeArr[i][1];
        if (curCol !== lastCol) {
            lastCol = curCol;
            resArr.push([]);
        }
        resArr[resArr.length - 1].push(nodeArr[i][2]);
    }

    return resArr;
};

复杂度分析

ViviXu-qiqi commented 2 years ago
var verticalTraversal = function(root) {
    if(!root) return [];
    let queue = [[root, 0, 0]];
    let objMap = new Map();
    let min = Infinity;
    let max = -Infinity;
    let finalArr = [];
    while(queue.length > 0) {
        let first = queue.pop();
        let nodeObj = first[0];
        let scaleLevel = first[1];
        let depth = first[2];
        min = Math.min(scaleLevel, min);
        max = Math.max(scaleLevel, max);
        if(objMap.has(scaleLevel)) {
            let arr = objMap.get(scaleLevel);
            arr.push([nodeObj, depth]);
            objMap.set(scaleLevel, arr);
        } else {
            objMap.set(scaleLevel, [[nodeObj, depth]]);
        }
        if(nodeObj.left) {
            queue.unshift([nodeObj.left, scaleLevel-1, depth+1]);
        }
        if(nodeObj.right) {
            queue.unshift([nodeObj.right, scaleLevel+1, depth+1]);
        }
    };    
    for(let i=min; i<=max; i++) {
        let arr = objMap.get(i);
        arr.sort((a, b) => {
            if(a[1] === b[1]) {
                return a[0].val - b[0].val;
            }
            return a[1] - b[1];
        })
        arr = arr.map((elem) => elem[0].val);
        finalArr.push(arr);
    }
    return finalArr;
};
LQyt2012 commented 2 years ago

思路

深度优先遍历,用元组记录节点的数据,(行,列,节点值)。这也是排序的关键字

代码

class Solution:
    def __init__(self):
        self.nodes = []

    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        self.dfs(root, 0, 0)
        self.nodes.sort()
        ans, lastcol = list(), float("-inf")

        for col, row, value in self.nodes:
            if col != lastcol:
                lastcol = col
                ans.append(list())
            ans[-1].append(value)

        return ans

    def dfs(self, node:TreeNode, row:int, col:int) -> None:
        if not node:
            return

        self.nodes.append((col, row, node.val))
        self.dfs(node.left, row + 1, col - 1)
        self.dfs(node.right, row + 1, col + 1)

复杂度分析

时间复杂度分析:O(NlogN),遍历O(N),主要在排序的复杂度O(NlogN) 空间复杂度分析:O(N)

biscuit279 commented 2 years ago

思路:

三层的哈希表,分别按照x,y,val排序

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        seen = collections.defaultdict(lambda: collections.defaultdict(list))
        def dfs(root, x=0, y=0):
            if not root:
                return
            seen[x][y].append(root.val)
            dfs(root.left, x-1, y+1)
            dfs(root.right, x+1, y+1)
        dfs(root)
        ans = []
        for x in sorted(seen):
            level = []
            for y in sorted(seen[x]):
                level += sorted(v for v in seen[x][y])
            ans.append(level)
        return ans 

时间复杂度:O(nlogn) 空间复杂度:O(n)

pong991 commented 2 years ago

思路

DFS, 先序遍历,记录每个节点的row和col,存储到map中,map中col为key值,value为对象数组[{row: row, val: root.val}]。

对map的key排序,遍历key获取map的值,将取出来的数组根据row和val的值排序(先比较row的大小,row相同再比较val),再将排序好的数组push到结果数组res中。

map: { 0:[ {row: row, val: root.val} ] }

代码 var verticalTraversal = function(root) { let map = new Map(); let keys = [], res = []; let preOrder = function(root, row, col) { if (!root) return; if (map.has(col)) map.get(col).push({row: row, val: root.val}); else { map.set(col, [{row: row, val: root.val}]); keys.push(col); } preOrder(root.left, row + 1, col - 1); preOrder(root.right, row + 1, col + 1); }; preOrder(root, 0, 0); keys.sort((a,b) => { return a - b; }); for (let i = 0; i < keys.length; i++) { let arr = map.get(keys[i]); arr.sort((a,b) => { if (a.row === b.row) return a.val - b.val; else return a.row - b.row; }); res.push(arr.map(val => {return val.val})); } return res; }; 复杂度分析 time: O(nlogn) space: O(n)

liuguang520-lab commented 2 years ago

思路

选一种遍历方式将树的节点值进行保存,同时还有行和列,然后对列进行排行

code

class Solution {
public:
    vector<tuple<int,int,int>> node; 
    void dfs(TreeNode* root, int row, int col)
    {
        if(root==nullptr)
        {
            return;
        }
        node.emplace_back(col,row,root->val);
        dfs(root->left,row+1,col-1);
        dfs(root->right,row+1,col+1);
    }
    vector<vector<int>> verticalTraversal(TreeNode* root) {
        dfs(root,0,0);
        sort(node.begin(),node.end());//进行排序,按照列行值。
        int last_col = INT_MIN;
        vector<vector<int>> result;
        for(const auto& [col,row,val] : node)
        {
            if(col != last_col)
            {
                last_col = col;
                result.emplace_back();//只是创建下一个数组
            }
            result.back().emplace_back(val);
        }
        return result;
    }
};

复杂度分析

duke-github commented 2 years ago

思路

对树进行遍历并记录 值 x y 记录, 将记录之后的数值排序

复杂度

时间复杂度:O(n log n) 空间复杂度:O(n)

代码

class Solution {
    Map<TreeNode, int[]> map = new HashMap<>(); // col, row, val
    public List<List<Integer>> verticalTraversal(TreeNode root) {
        map.put(root, new int[]{0, 0, root.val});
        dfs(root);
        List<int[]> list = new ArrayList<>(map.values());
        Collections.sort(list, (a, b)->{
            if (a[0] != b[0]) {
                return a[0] - b[0];
            }
            if (a[1] != b[1]) {
                return a[1] - b[1];
            }
            return a[2] - b[2];
        });
        int n = list.size();
        List<List<Integer>> ans = new ArrayList<>();
        for (int i = 0; i < n; ) {
            int j = i;
            List<Integer> tmp = new ArrayList<>();
            while (j < n && list.get(j)[0] == list.get(i)[0]) {
                tmp.add(list.get(j++)[2]);
            }
            ans.add(tmp);
            i = j;
        }
        return ans;
    }
    void dfs(TreeNode root) {
        if (root == null) return ;
        int[] info = map.get(root);
        int col = info[0], row = info[1], val = info[2];
        if (root.left != null) {
            map.put(root.left, new int[]{col - 1, row + 1, root.left.val});
            dfs(root.left);
        }
        if (root.right != null) {
            map.put(root.right, new int[]{col + 1, row + 1, root.right.val});
            dfs(root.right);
        }
    }
}
mo660 commented 2 years ago

思路

使用DFS遍历,用node结构体存储x,y,val。

代码

class Solution {
public:
    struct node{
        int val;
        int x;
        int y;
        node(int v,int X,int Y):val(v),x(X),y(Y){};
    };
    static bool cmp(node a, node b){
        if (a.x^b.x)
            return a.x<b.x;
        if (a.y^b.y)
            return a.y<b.y;
        return a.val<b.val;
    }
    vector<node> a;
    int minx=1000,maxx=-1000;
    vector<vector<int>> verticalTraversal(TreeNode* root) {
        dfs(root, 0, 0);
        sort(a.begin(),a.end(),cmp);
        vector<vector<int>>ans(maxx-minx+1);
        for (auto i : a){
            ans[i.x - minx].push_back(i.val);
        }
        return ans;
    }
    void dfs(TreeNode* root, int x, int y){
        if (root == nullptr)
            return;
        if (x < minx)
            minx = x;
        if (x > maxx)
            maxx = x;
        a.push_back(node(root->val,x,y));
        dfs(root->left, x-1, y+1);
        dfs(root->right, x+1, y+1);
    }
};
Orangejuz commented 2 years ago

思路

dfs 从根节点开始,对整棵树进行一次遍历,并在遍历过程中使用数组记录信息

代码


class Solution:
    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        nodes = list()

        def dfs(node: TreeNode, row: int, col: int) -> None:
            if not node:
                return

            nodes.append((col, row, node.val))
            dfs(node.left, row + 1, col - 1)
            dfs(node.right, row + 1, col + 1)

        dfs(root, 0, 0)
        nodes.sort()
        ans, lastcol = list(), float("-inf")

        for col, row, value in nodes:
            if col != lastcol:
                lastcol = col
                ans.append(list())
            ans[-1].append(value)

        return ans

复杂度分析

时间:O(nlogn) 空间:O(n)

youxucoding commented 2 years ago

4月18日

【day18】

leetcode.987. 二叉树的垂序遍历

难度 困难

给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。

对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row + 1, col - 1)(row + 1, col + 1) 。树的根结点位于 (0, 0)

二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。

返回二叉树的 垂序遍历 序列。

示例 1:

img

输入:root = [3,9,20,null,null,15,7]
输出:[[9],[3,15],[20],[7]]
解释:
列 -1 :只有结点 9 在此列中。
列  0 :只有结点 3 和 15 在此列中,按从上到下顺序。
列  1 :只有结点 20 在此列中。
列  2 :只有结点 7 在此列中。

思路:

首先遍历整个树,将结点信息保存下来(col,row,val),按照规则进行排序;排序的规则是:首先按列从小到大,再按行从小到大,最后同行同列按照val从小到大,使用Collections.sort(list,compare)的自定义排序,这个如果不会,先学一下。最后按照排好的顺序,『按列』构建出结果list。

代码实现:

class Solution {
    List<int[]> list = new ArrayList();
    public List<List<Integer>> verticalTraversal(TreeNode root) {
        dfs(root,0,0);
        Collections.sort(list, new Comparator<int[]>() {

            public int compare(int[] o1, int[] o2) {
                if(o1[0] != o2[0])
                    return o1[0]-o2[0];
                if(o1[1] != o2[1])
                    return o1[1]-o2[1];
                return o1[2]-o2[2];
            }
        });
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        int last = Integer.MIN_VALUE;
        int size = 0;
        for(int[] arr : list){
            int col = arr[0];
            int row = arr[1];
            int value = arr[2];
            if(col != last){
                last = col;
                res.add(new ArrayList<Integer>());
                size++;
            }
            res.get(size-1).add(value);
        }
        return res;

    }
    void dfs(TreeNode root,int row,int col){
        if(root == null){
            return ;
        }
        list.add(new int[]{col,row,root.val});
        dfs(root.left,++row,--col);
        row--;
        col++;
        dfs(root.right,++row,++col);
        row--;
        col--;

    }
}

复杂度分析:

liuajingliu commented 2 years ago

解题思路

BFS

代码实现

javaScript

/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var verticalTraversal = function(root) {
  if(!root) return root
  const result = []
  const obj = new Map();
  // [node, rowVal, colVal]
  const queue = [[root,0, 0]]

  while(queue.length){
    const [node, row, col] = queue.shift()
    obj.set(col, (obj.get(col) || []).concat([[node.val, row]]))
    node.left && queue.push([node.left, row + 1, col - 1 ])
    node.right && queue.push([node.right, row + 1 , col + 1 ])
  }

  // sort
  let sortedKeys = [...obj.keys()].sort((a,b) => a - b)

  for(const key of sortedKeys){
    let temp = obj.get(key)
    temp = temp.sort((a,b) => {
      if(a[1] != b[1]){
        return a[1] - b[1]
      }
      return a[0] - b[0]
    })
    result.push(temp.map((item) => item[0]))
  }
  return result;
};

复杂度分析

revisegoal commented 2 years ago

DFS + 优先队列

duantao74520 commented 2 years ago

思路:

  1. 用一个vector保存坐标与值。

  2.    struct ValNode {
           int x;
           int y;
           int val;
       };
  3. DFS遍历,并将坐标与值写入

  4. 按 y x val排序

  5. 打印

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    // DFS 遍历所有节点,并且把节点坐标放到暂存区中
    void DFS(TreeNode* root, int x, int y) {
        if (root == nullptr) {
            return;
        }
        ValNode val_node{.x = x, .y=y, .val=root->val};
        dp.emplace_back(val_node);
        DFS(root->left, x+1, y-1);
        DFS(root->right, x+1, y+1);
    }
    vector<vector<int>> verticalTraversal(TreeNode* root) {
        DFS(root, 0, 0);
        // 排序dp 按照  y x val 排序
        std::sort(dp.begin(), dp.end(), [](const ValNode& a, const ValNode&b){
            if (a.y < b.y) {
                return true;
            } else if (a.y > b.y) {
                return false;
            } else {
                if (a.x < b.x) {
                    return true;
                } else if (a.x > b.x) {
                    return false;
                } else {
                    return a.val <= b.val;
                }
            }
        });
        // 打印
        vector<vector<int>> ret_vec;
        int last_y =  -10001;
        vector<int> tmp_dp;
        for (const auto& node_val : dp) {
            if (node_val.y != last_y && !tmp_dp.empty()) {
                ret_vec.emplace_back(tmp_dp);
                tmp_dp.clear();
            }
            tmp_dp.emplace_back(node_val.val);
            last_y = node_val.y;
        }
        if (!tmp_dp.empty()) {
            ret_vec.emplace_back(tmp_dp);
        }
        return ret_vec;
    }
private:
    struct ValNode {
        int x;
        int y;
        int val;
    };
    vector<ValNode> dp;
};

复杂度:

时间: O(nLOG(n));

空间: O(N)

revisegoal commented 2 years ago

DFS + 优先队列

winrunwang commented 2 years ago

DFS + 优先级队列

public List<List> verticalTraversal(TreeNode root) { List<int[]> nodes = new ArrayList<int[]>(); dfs(root, 0, 0, nodes); Collections.sort(nodes, new Comparator<int[]>() { public int compare(int[] tuple1, int[] tuple2) { if (tuple1[0] != tuple2[0]) { return tuple1[0] - tuple2[0]; } else if (tuple1[1] != tuple2[1]) { return tuple1[1] - tuple2[1]; } else { return tuple1[2] - tuple2[2]; } } }); List<List> ans = new ArrayList<List>(); int size = 0; int lastcol = Integer.MIN_VALUE; for (int[] tuple : nodes) { int col = tuple[0], row = tuple[1], value = tuple[2]; if (col != lastcol) { lastcol = col; ans.add(new ArrayList()); size++; } ans.get(size - 1).add(value); } return ans; }

public void dfs(TreeNode node, int row, int col, List<int[]> nodes) {
    if (node == null) {
        return;
    }
    nodes.add(new int[]{col, row, node.val});
    dfs(node.left, row + 1, col - 1, nodes);
    dfs(node.right, row + 1, col + 1, nodes);
}
houyanlu commented 2 years ago

思路

BFS 需要使用一个map来存储不同y值的节点 我们每次遍历的节点的y值是相同的,那么我们可以将此次遍历的节点都存储到一个临时的map中,当遍历结束后,我们可以遍历这个临时的map,根据不同的y值去从到大排序。 最后将排好序的节点再加入到我们的第一个map即可。

代码


/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    struct Node {
        int x { 0 };
        int y { 0 };
        TreeNode *root { nullptr };
        Node() {}
        Node(int a, int b, TreeNode *c) : x(a), y(b), root(c) {}
    };

    vector <vector <int>> ans;
    map <int, vector<int>> ss;

    vector<vector<int>> verticalTraversal(TreeNode* root) {
        if (root == nullptr) {
            return ans;         
        }
        queue <Node> q;
        q.push({0, 0, root});
        while (!q.empty()) {
            int n = q.size();
            map <int, vector<int>> tmp; // 临时的 map
            for(int i = 0; i < n; i++) {
                auto k = q.front();
                q.pop();
                tmp[k.y].push_back(k.root->val);
                if(k.root->left) q.push({k.x + 1, k.y - 1, k.root->left});
                if(k.root->right) q.push({k.x + 1, k.y + 1, k.root->right});
            }

            for (auto &[x, y] : tmp) { // 遍历
                sort(y.begin(), y.end());  // 排序
                for (auto &c : y) {
                    ss[x].push_back(c);  // 将节点加入第一个 map(ss) 中
                }
            }
            tmp.clear();
        }
        for(auto &[x, y] : ss) {
            ans.push_back(y);
        } 
        return ans;
    }
};

复杂度分析

bzlff commented 2 years ago

class Solution:
    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        hashmap = defaultdict(list)
        def dfs(node, x, y):
            if not node:
                return
            hashmap[y].append((x,node.val))
            dfs(node.left, x+1, y-1)
            dfs(node.right,x+1, y+1)

        dfs(root, 0, 0)
        return [list(zip(*sorted(hashmap[i])))[1] for i in sorted(hashmap.keys())]
xil324 commented 2 years ago
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def verticalTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        res = []; 
        queue = collections.deque(); 
        queue.append((root,0,0));
        while queue:
            curr, x, y = queue.popleft();
            if curr:
                res.append([curr.val, x,y]);     
                queue.append((curr.left, x+1,y-1));
                queue.append((curr.right,x+1,y+1)); 

        ans = [];
        res = sorted(res, key = lambda x : (x[2], x[1], x[0]));
        print(res)
        ans = OrderedDict();
        for value,row, column  in res:
            if column in ans:
                ans[column].append(value); 
            else:
                ans[column] = [value]; 

        return ans.values();

time complexity: O(nlogn), visited every node of the tree and sorting takes o(nlogn)

ha0cheng commented 2 years ago

思路:层次遍历,先处理一层的节点,然后将这一层的节点排序后,加入总的结果中,用字典来存储结果,字典的key是列的值。

复杂度分析: 时间复杂度: O(N+Mlog M+QlogQ) , 主要是层次遍历的复杂度O(N), 以及排序的复杂度O(MlogM),其中M是最后的column的个数,Q是最坏情况下同一层的节点都在同一列,大致为O(NlogN). 空间复杂度:O(N), 哈希表的大小与节点个数同阶

代码如下:

class Solution:
    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        re = {}
        node_queue = [root]
        col_queue = [0]
        while node_queue:
            length = len(node_queue)
            layer_re = {}
            for _ in range(length):

                node = node_queue.pop(0)
                col = col_queue.pop(0)
                if col not in layer_re.keys():
                    layer_re[col] = [node.val]
                else:
                    layer_re[col].append(node.val)

                if node.left:
                    node_queue.append(node.left)
                    col_queue.append(col-1)
                if node.right:
                    node_queue.append(node.right)
                    col_queue.append(col+1)

            for i in layer_re.keys():
                layer_re[i].sort()
                if i not in re.keys():
                    re[i] = layer_re[i]
                else:
                    re[i].extend(layer_re[i])

        Col = list(re.keys())
        Col.sort()
        result = []
        for col in Col:
            result.append(re[col])
        return result 
zzz607 commented 2 years ago

思路

中序遍历,给每个节点产生一个(row, col)坐标,然后收集坐标进行排序即可。 但是排序那段代码看上去比较的啰嗦,后面看看其它答案优化一下吧

代码

func verticalTraversal(root *TreeNode) [][]int {
    // map[column]map[line][]int
    var nodes = make(map[int]map[int][]int, 0)

    var travel func(node *TreeNode, row, col int)
    travel = func(node *TreeNode, row, col int) {
        if node == nil {
            return
        }

        if _, ok := nodes[col]; !ok {
            nodes[col] = map[int][]int{row: {node.Val}}
        } else if _, ok = nodes[col][row]; !ok {
            nodes[col][row] = []int{node.Val}
        } else {
            nodes[col][row] = append(nodes[col][row], node.Val)
        }

        travel(node.Left, row + 1, col - 1)
        travel(node.Right, row + 1, col + 1)
    }
    travel(root, 0, 0)
    // fmt.Printf("nodes: %+v\n", nodes)

    ret := make([][]int, 0, len(nodes))

    // 列排序
    colKeys := make([]int, 0, len(nodes))
    for k := range nodes {
        colKeys = append(colKeys, k)
    }
    sort.Ints(colKeys)
    // fmt.Printf("colKeys: %+v\n", colKeys)
    for _, k := range colKeys {
        // 行排序
        rowKeys := make([]int, 0, len(nodes[k]))
        for i := range nodes[k] {
            rowKeys = append(rowKeys, i)
        }
        sort.Ints(rowKeys)
        // fmt.Printf("colKey: %d, rowKeys: %+v\n", k, rowKeys)

        colRet := make([]int, 0)
        for _, r := range rowKeys {
            rowData := nodes[k][r]
            sort.Ints(rowData)
            colRet = append(colRet, rowData...)
        }
        ret = append(ret, colRet)
    }

    return ret
}

复杂度分析

m908 commented 2 years ago
class Solution {
public:
    void helper(TreeNode* p, int x, int y){
        if(!p) return;
        map[x].insert(y * 10000 + p->val);
        helper(p->left, x-1, y+1);
        helper(p->right, x+1, y+1);
        return;
    }

    vector<vector<int>> verticalTraversal(TreeNode* root) {
        helper(root, 0, 0);
        vector<vector<int>> result;
        for(auto x:map){
            vector<int> curr;
            for(auto y:x.second) curr.push_back(y % 10000);
            result.push_back(curr);
        }
        return result;
    }

private:
     map<int,set<int>> map;
};
Geek-LX commented 2 years ago

4.18

思路:

记录每一个列出现的所有数字(带行数),按列排序,按行排序,按值排序即可。

代码:

class Solution:
    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        hashmap = defaultdict(list)
        def dfs(node, x, y):
            if not node:
                return
            hashmap[y].append((x,node.val))
            dfs(node.left, x+1, y-1)
            dfs(node.right,x+1, y+1)

        dfs(root, 0, 0)
        return [list(zip(*sorted(hashmap[i])))[1] for i in sorted(hashmap.keys())]
taojin1992 commented 2 years ago
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */

/*
# Plan1:
preorder
- track depth
- vertical distance (go left: - 1, right + 1)

nested map:
- key sorted by vertical distances (its values sorted by treenode val)

TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>

no need to specifically track minVertical, maxVertical if we use treemap

Time:
touch each node once during dfs, O(n)
offer each node to pq and poll each node from pq
O(nlogn)

Space: 
map: O(n), n = number of nodes
dfs: O(height)

# Plan2: BFS + hashmap x->pairs
Time:
- bfs, touch on each node once
- Collections.sort on each list of same x, 
assume: i number of possible x's, on average j nodes for each

i * jlog(j) = n log j, n = number of nodes
- add to list O(n)

Space: queue O(widest) = O[(n+1)/2] = O(n)
hashmap: store number of pairs = number of nodes, O(n)
->assume: i number of possible x's, on average j nodes for each, either way i * j = n

*/

class Solution {
    public List<List<Integer>> verticalTraversal1(TreeNode root) {
        TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>> VThenDepthMap = new TreeMap<>();
        dfs(root, 0, 0, VThenDepthMap);

        List<List<Integer>> traversal = new ArrayList<>();
        // when we traverse, vertical is sorted (vertically, go from left to right)
        for (TreeMap<Integer, PriorityQueue<Integer>> sortedDtosortedVals : VThenDepthMap.values()) {
            traversal.add(new ArrayList<>()); 
            // start from min vertical distance, go from top to bottom, if same depth (also same vertical), smaller comes first

            for (PriorityQueue<Integer> sortedValsOfSameD : sortedDtosortedVals.values()) {
                while (!sortedValsOfSameD.isEmpty()) {
                    traversal.get(traversal.size() - 1).add(sortedValsOfSameD.poll()); // poll() once for each node, O(nlogn)
                }
            }
        }
        return traversal;
    }

    // x: vertical, y : level
    // time: for each node val, need to be inserted to the right priorityqueue O(nlogn) 
    // touch each node once O(n)
    // intotal O(nlogn)
    private void dfs(TreeNode cur, int x, int y, TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>> VThenDepthMap) {
        if (cur == null) {
            return;
        }

        if (!VThenDepthMap.containsKey(x)) {
            VThenDepthMap.put(x, new TreeMap<> ());
        }

        if (!VThenDepthMap.get(x).containsKey(y)) {
            VThenDepthMap.get(x).put(y, new PriorityQueue<>());

        }
        VThenDepthMap.get(x).get(y).offer(cur.val);

        dfs(cur.left, x - 1, y + 1, VThenDepthMap);
        dfs(cur.right, x + 1, y + 1, VThenDepthMap);
    }

    // Method 2: level-order + hashmap
    class Pair {
        TreeNode node;
        int x;
        int y;

        Pair(TreeNode node, int x, int y) {
            this.node = node;
            this.x = x;
            this.y = y;
        }
    }

    public List<List<Integer>> verticalTraversal(TreeNode root) {
        List<List<Integer>> traversal = new ArrayList<>();
        // vertical distance -> list of pairs
        Map<Integer, List<Pair>> xToPairsMap = new HashMap<>();
        // BFS
        Queue<Pair> queue = new LinkedList<>();
        queue.offer(new Pair(root, 0, 0));
        int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
        // BFS: O(n) time
        while (!queue.isEmpty()) {

            Pair cur = queue.poll();

            if (cur.node == null) System.out.println(queue.size());

            minX = Math.min(minX, cur.x);
            maxX = Math.max(maxX, cur.x);

            if (!xToPairsMap.containsKey(cur.x)) {
                xToPairsMap.put(cur.x, new ArrayList<>());
            }
            xToPairsMap.get(cur.x).add(cur);

            if (cur.node.left != null) {
                queue.offer(new Pair(cur.node.left, cur.x - 1, cur.y + 1));
            }
            if (cur.node.right != null) {
                queue.offer(new Pair(cur.node.right, cur.x + 1, cur.y + 1));
            }

        }

        // sort
        for (int v = minX; v <= maxX; v++) {
            List<Pair> sameXPairs = xToPairsMap.get(v);
            // sort by y (depth) first and then value
            // if depth/y is the same, smaller value comes first
            Collections.sort(sameXPairs, new Comparator<Pair>() {
                public int compare(Pair a, Pair b) {
                    if (a.y == b.y) {
                        return a.node.val - b.node.val;
                    }
                    return 0; // bfs puts pairs of smaller depth first
                }
            });

            List<Integer> sameX = new ArrayList<>();
            for (Pair sameXPair : sameXPairs) {
                sameX.add(sameXPair.node.val);
            }
            traversal.add(sameX);
        }

        return traversal;
    }

}
ZETAVI commented 2 years ago

思路

自定义排序

语言

java

代码

 public List<List<Integer>> verticalTraversal(TreeNode root) {
        ArrayList<int[]> list = new ArrayList<>();
        DFS(root,0,0,list);
        Collections.sort(list, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if (o1[0]!=o2[0]){
                    return o1[0]-o2[0];
                }else {
                    if (o1[1]!=o2[1]){
                        return o1[1]-o2[1];
                    }else {
                        return o1[2]-o2[2];
                    }
                }
            }
        });
        List<List<Integer>> ans = new ArrayList<>();
        int size=0;
        int left=Integer.MIN_VALUE;
        for (int[] t:list){
            if (t[0]!=left){
                left=t[0];
                ans.add(new ArrayList<>());
                size++;
            }
            ans.get(size-1).add(t[2]);
        }
        return ans;
    }

    private void DFS(TreeNode root, int row, int col, ArrayList<int[]> list) {
        if (root==null)return;
        list.add(new int[]{col,row,root.val});
        DFS(root.left,row+1,col-1,list);
        DFS(root.right,row+1,col+1,list);
    }

复杂度分析N

maggiexie00 commented 2 years ago

思路

遍历树,存储值,row, col,接着对树节点的列表排序,最后按要求生成新列表。

代码

def verticalTraversal(self, root) :
    nodes = list()

    def dfs(node: TreeNode, row: int, col: int) -> None:
        if not node:
            return

        nodes.append((col, row, node.val))
        dfs(node.left, row + 1, col - 1)
        dfs(node.right, row + 1, col + 1)

    dfs(root, 0, 0)
    nodes.sort()
    ans, lastcol = list(), float("-inf")

    for col, row, value in nodes:
        if col != lastcol:
            lastcol = col
            ans.append(list())
        ans[-1].append(value)

    return ans

复杂度

时间 o(n log n) 首先遍历花费o(n), 排序花费o(nlogn),最后遍历节点列表花费o(n) 空间 o(n)

bigboom666 commented 2 years ago

思路

DFS + 排序

code

class Solution {
    Map<Integer, Map<Integer, List<Integer>>> hashmap;
    public List<List<Integer>> verticalTraversal(TreeNode root) {
        hashmap = new HashMap<>();
        dfs(root, 0, 0);

        List<List<Integer>> res = new ArrayList<>();
        List<Integer> tmp = new ArrayList<>();
        List<Integer> js = new ArrayList(hashmap.keySet());
        Collections.sort(js);
        for(Integer j : js){
            tmp = new ArrayList<>();
            Map<Integer, List<Integer>> map = hashmap.get(j);
            List<Integer> is = new ArrayList(map.keySet());
            Collections.sort(is);
            for(Integer i : is){
                List<Integer> values = map.get(i);
                Collections.sort(values);
                tmp.addAll(values);
            }
            res.add(tmp);
        }
        return res;
    }
    private void dfs(TreeNode node, int j, int i){
        if(node == null){
            return;
        }
        if(!hashmap.containsKey(j)){
            hashmap.put(j, new HashMap<>());
        }
        if(!hashmap.get(j).containsKey(i)){
            hashmap.get(j).put(i, new ArrayList<>());
        }
        hashmap.get(j).get(i).add(node.val);
        dfs(node.left, j - 1, i + 1);
        dfs(node.right, j + 1, i + 1);
    }
}

复杂度

时间:O(NlogN)
空间:O(N)

tensorstart commented 2 years ago

思路

先dfs遍历存储坐标数组,然后按照题目要求进行输出

代码

var verticalTraversal = function(root) {
    if (!root) return [];
    let treenodeArr=[];
    let dfs=function (root,x,y){
        if (!root) return;
        treenodeArr.push([x,y,root.val]);
        dfs(root.left,x-1,y+1)
        dfs(root.right,x+1,y+1);
    };
    dfs(root,0,0);
    treenodeArr=treenodeArr.sort((a,b)=>{
        if (a[0]!==b[0]) return a[0]-b[0];
        else if (a[1]!==b[1]) return a[1]-b[1];
        else return a[2]-b[2];
    })

    let curValOfX = treenodeArr[0][0]; 
    let res = [[treenodeArr[0][2]]];
    for (let i = 1; i < treenodeArr.length; i++) {
        let location = treenodeArr[i];
        let x = location[0];
        if (x === curValOfX) { 
            let last = res[res.length - 1];
            last.push(location[2]);
        } else { 
            res.push([location[2]]);
        }
    }

    return res;

};
yinhaoti commented 2 years ago
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def verticalTraversal(self, root: Optional[TreeNode]) -> List[List[int]]:
        """
        Ideas:
            {
                2: [4],
                1: [2],
                0: [5, 1, 6}
            } 
            ->
            {
                2: {2: [4]},
                1: {1: [2]},
                0: {0:[1], 2:[5, 6]}
            } 
            save in dict + dict + list
            sort x, sort y, sort value
        TC: O(n) + O(nlogn) = O(nlogn)
        SC: O(n)
        """

        seen = collections.defaultdict(lambda: collections.defaultdict(list))

        def dfs(root, x, y):
            if not root: return
            dfs(root.left,x - 1, y + 1)
            seen[x][y].append(root.val)
            dfs(root.right, x + 1, y + 1)
        dfs(root, 0, 0)

        ans = []
        for x in sorted(seen):
            level = []
            for y in sorted(seen[x]):
                level += sorted(seen[x][y])
            ans.append(level)
        return ans
currybeefer commented 2 years ago

思路:这题已经给出提示了,所有的二叉树节点都可以用坐标表示。那么我们只需要DFS遍历一遍给所有节点标记对应的坐标并且加入到一个集合里,然后按照要求的排序方式输出就好啦 代码:代码参考官方题解

struct node
    {
        int val;
        int x;
        int y;
        node(int i_val, int i_x,int i_y):val(i_val),x(i_x),y(i_y){};
    };
    static bool cmp(node a,node b)
    {
        if(a.x^b.x)
            return a.x<b.x;
        if(a.y^b.y)
            return a.y<b.y;

        return a.val<b.val;
    }
    vector<node> nodeArr;
    int minX=INT_MAX;
    int maxX=INT_MIN;
    vector<vector<int>> verticalTraversal(TreeNode* root) 
    {
        dfs(root,0,0);
        sort(nodeArr.begin(),nodeArr.end(),cmp);
        vector<vector<int>> res(maxX-minX+1);
        for(node son:nodeArr)
        {
            res[son.x-minX].push_back(son.val);
        }
        return res;
    }
    void dfs(TreeNode* root,int x,int y)
    {
        if(root==nullptr) return;

        if(x<minX)
            minX=x;
        if(x>maxX)
            maxX=x;

        nodeArr.push_back(node(root->val,x,y));
        dfs(root->left,x-1,y+1);
        dfs(root->right,x+1,y+1);
    }

复杂度: 时间复杂度:O(nlogn) 空间复杂度:O(n)

JasonHe-WQ commented 2 years ago

代码:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
        q = [root]
        min = 0
        max = 0
        if not root:
            return None
        lo = [[[root.val, 0, 0]]]
        level = 0       
        while q:
            child=[]
            lo.append([])  
            for i in range(len(q)):
                if q[i].left:
                    child.append(q[i].left)
                    lo[-1].append([q[i].left.val, lo[level][i][1] + 1, lo[level][i][2] - 1])
                if q[i].right:
                    child.append(q[i].right)
                    lo[-1].append([q[i].right.val, lo[level][i][1] + 1, lo[level][i][2] + 1])
            q = child
            level += 1
            if not child:
                lo.pop()
        new = []
        for i in lo:
            for j in i:
                new.append(j)
        new = sorted(new,key = lambda x: x[2])
        col = []
        tar = []
        row = {}
        temp = []
        for i in new:
            if i[2] not in col:
                tar.append([])
                col.append(i[2])
                row.clear()
            if i[1]not in row:
                tar[-1].append(i[0])
                row[i[1]] = 1
            else:
                while row[i[1]]>0:
                    temp.append(tar[-1].pop())
                    row[i[1]] -= 1
                temp.append(i[0])
                temp.sort()
                row[i[1]] = len(temp)
                tar[-1].extend(temp)
                temp = []

        return tar
XXjo commented 2 years ago

思路

dfs遍历树,使其形成{col: {row :[val1, val2...]}}的结构,然后分别对col、row以及[val1,val2...]进行排序即可

代码

var verticalTraversal = function(root) {
    let nodes = {};
    dfs(root, 0, 0, nodes);
    let res = [];
    for(let col of Object.keys(nodes).sort((a, b) => a - b)){
        let temp = [];
        for(let row of Object.keys(nodes[col]).sort((a, b) => a - b)){
            if(nodes[col][row].length == 1){
                temp = temp.concat(nodes[col][row]);
            }
            else{
                temp = temp.concat(nodes[col][row].sort((a, b) => a - b));  
            }
        }
        res.push(temp);
    }
    return res;
};

var dfs = function(node, row, col, nodes){
    if(node === null) return;
    if(col in nodes){
        if(row in nodes[col]){
            nodes[col][row].push(node.val);
        }
        else{
            let temp = nodes[col];
            temp[row] = [node.val];
            nodes[col] = temp;
        }
    }
    else{
       let temp = {};
       temp[row] = [node.val];
       nodes[col] = temp;
    }
    dfs(node.left, row + 1, col - 1, nodes);
    dfs(node.right, row + 1, col + 1, nodes);
}
Jessie725 commented 2 years ago

Idea

BFS: use a priorityQueue instead of queue to make each level sorted by row than by node.val Put verticalNode into TreeMap to sort col during BFS Data structure: Use TreeMap sort col; Use PriorityQueue sort row then sort node.val map holds the result

Code

class Solution {
    public List<List<Integer>> verticalTraversal(TreeNode root) {
        // sort by row then node.val
        PriorityQueue<VerticalNode> q  = new PriorityQueue<>((a, b) -> {
            if (a.row == b.row) {
                return a.node.val - b.node.val;
            }
            else {
                return a.row - b.row;
            }
            }); 
        Map<Integer, List<Integer>>map = new TreeMap<>(); // key is col, sort by col

        q.offer(new VerticalNode(root, 0, 0));
        while (!q.isEmpty()) {
            VerticalNode curr = q.poll();
            List<Integer> list = map.getOrDefault(curr.col, new ArrayList<>());
            list.add(curr.node.val);
            map.put(curr.col, list);

            if (curr.node.left != null) {
                q.offer(new VerticalNode(curr.node.left, curr.col-1, curr.row+1));
            }
            if (curr.node.right != null) {
                q.offer(new VerticalNode(curr.node.right, curr.col+1, curr.row+1));
            }
        }

        List<List<Integer>> res = new ArrayList<>();
        for (List<Integer> values : map.values()) {
            res.add(values);
        }
        return res;
    }

    class VerticalNode {
        TreeNode node;
        int col;
        int row;

        public VerticalNode(TreeNode n, int c, int r) {
            node = n;
            col = c;
            row = r;
        }
    }
}

Complexity

Time: O(nlogn) n times heapify Space: O(n)

Yongxi-Zhou commented 2 years ago

思路

用map记录每个坐标节点list的值,最后加进来的时候要把同坐标的list排序

代码

    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, val=0, left=None, right=None):
    #         self.val = val
    #         self.left = left
    #         self.right = right
    class Solution(object):
        def verticalTraversal(self, root):
            """
            :type root: TreeNode
            :rtype: List[List[int]]
            """
            self.seen = collections.defaultdict(lambda: collections.defaultdict(list))
            self.dfs(root, 0, 0)

            res = []
            for col in sorted(self.seen):
                level = []
                for row in sorted(self.seen[col]):
                    level += list(v for v in sorted(self.seen[col][row]))
                res.append(level[:])
            return res

        def dfs(self, root, row, col):
            if not root:
                return 
            self.seen[col][row].append(root.val)
            self.dfs(root.left, row + 1, col - 1)
            self.dfs(root.right, row + 1, col + 1)

复杂度

time O(NlogN) space O(N)