【Lintcode】651. Binary Tree Vertical Order Traversal

题目地址:

https://www.lintcode.com/problem/binary-tree-vertical-order-traversal/description

给定一棵二叉树,要求垂直对其进行遍历,想象树根的坐标是 ( 0 , 0 ) (0,0) (0,0),对于每个节点 ( x , y ) (x,y) (x,y),其左右孩子的坐标分别是 ( x + 1 , y − 1 ) (x+1,y-1) (x+1,y1) ( x + 1 , y + 1 ) (x+1,y+1) (x+1,y+1)。遍历的结果应当是若干列表形成的一个大的列表,这些列表按 y y y的次序是从小到大。每个列表内部的数字应该按其在树中的深度由小到大排序。如果两个节点的坐标相等,则应该左边的在前右边的在后。

思路是DFS。开一个列表,存储每一列的节点,同时DFS的时候要将坐标作为参数不断传递下去,同时还需要记录一下 y = 0 y=0 y=0这个列对应的列表的下标是多少,这样才能知道一个节点应该加到哪个列表里面去。DFS的顺序按照先左子树后右子树来。但是还有一个问题,就是这样DFS之后,每个列表内部的节点不一定是按照深度排序的,所以还需要另外开一个类,存每个节点的深度,最后汇总答案的时候把每一列按照深度再排个序即可。代码如下:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Solution {
    
    // zeroIdx记录y = 0那一列对应的list的下标。
    // zeroIdx是实时更新的,所以要设为全局变量同步修改
    private int zeroIdx;
    
    class Pair {
        int val, depth;
    
        public Pair(int val, int depth) {
            this.val = val;
            this.depth = depth;
        }
    }
    
    /**
     * @param root: the root of tree
     * @return: the vertical order traversal
     */
    public List<List<Integer>> verticalOrder(TreeNode root) {
        // write your code here
        List<List<Integer>> res = new ArrayList<>();
        List<List<Pair>> lists = new ArrayList<>();
        dfs(root, 0, 0, lists);
    
    	// 对lists里每个list按照深度排序。
    	// 由于java里对于对象的排序是稳定的排序,所以不用担心左右的顺序会颠倒
        for (List<Pair> list : lists) {
            list.sort((p1, p2) -> Integer.compare(p1.depth, p2.depth));
            List<Integer> col = new ArrayList<>();
            for (Pair pair : list) {
                col.add(pair.val);
            }
            
            res.add(col);
        }
        
        return res;
    }
    
    private void dfs(TreeNode cur, int x, int y, List<List<Pair>> lists) {
        if (cur == null) {
            return;
        }
        
        if (zeroIdx + y < 0) {
            lists.add(0, new ArrayList<>());
            zeroIdx++;
        } else if (zeroIdx + y >= lists.size()) {
            lists.add(new ArrayList<>());
        }
        
        lists.get(zeroIdx + y).add(new Pair(cur.val, x));
        
        dfs(cur.left, x + 1, y - 1, lists);
        dfs(cur.right, x + 1, y + 1, lists);
    }
}

class TreeNode {
    int val;
    TreeNode left, right;
    
    public TreeNode(int val) {
        this.val = val;
    }
}

时间复杂度 O ( n + w h log ⁡ h + w 2 ) O(n+wh\log h+w^2) O(n+whlogh+w2) w w w是树的宽度, w 2 w^2 w2的意思是,在lists.add(0, new ArrayList<>())这一步,是需要将所有list后移的。如果这里用链表,虽然首尾插入时间 O ( 1 ) O(1) O(1),但是索引时间变大了,并不会减少复杂度。空间 O ( n ) O(n) O(n)

注解:
这里的时间复杂度还有优化的空间。我们可以两次DFS,第一次DFS的时候先不断向左走,把 y y y等于负的那部分list先new出来加进res,然后第二次DFS的时候再去执行上面代码中的逻辑。这样时间复杂度可以降到 O ( n + w h log ⁡ h ) O(n+wh\log h) O(n+whlogh)。当然在宽度不够宽的时候,改进其实有限。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值