该题的实现是本人自己的实现,脑子愚笨,肯定不是最好的实现,该文只是学习记录,如果能帮到你,是我的荣幸。JDK版本1.8
给定二叉树,按垂序遍历返回其结点值。
对位于 (X, Y) 的每个结点而言,其左右子结点分别位于 (X-1, Y-1) 和 (X+1, Y-1)。
把一条垂线从 X = -infinity 移动到 X = +infinity ,每当该垂线与结点接触时,我们按从上到下的顺序报告结点的值( Y 坐标递减)。
如果两个结点位置相同,则首先报告的结点值较小。
按 X 坐标顺序返回非空报告的列表。每个报告都有一个结点值列表。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree
输入:[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)。
大家看上面标出结点坐标的图。仔细观察,你会发现所谓的垂序遍历其实就是一个分类+排序的问题(在我的眼里是这样的理解的)。
遍历整个二叉树,同时得到每个结点的坐标和值。然后依据x值分类并排序,这样就会得到这样的结果:
可以看到,如果我们以X值分类,可以得到四类。分别是{(-1,-1)}、{(0,0),(0,-2)}、{(1,-1)}、{(2,-2)}
因为题目要求 ‘ 一条垂线从 X = -infinity 移动到 X = +infinity ’,所以以X分类还要对x进行升序排序。
对X分类排序之后,应题目要求按从上到下的顺序报告结点的值( Y 坐标递减)。如果两个结点位置相同,则首先报告的结点值较小。
我们还需要对每个排好序的分类中在进行排序,排序思路:依照y的大小进行降序排序,如果Y相等那就在比较他们的值,也是降序。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//这个HashMap是实现的关键,它就是我们分类的映射
//key:x 也就是以x对应的值为一类
//value: List 这个list对应同一类的Entry
//Entry: 包装以X分类好之后每个结点的信息,成员变量有y和结点值val
HashMap<Integer, List<Entry>> map = new HashMap<>();
public List<List<Integer>> verticalTraversal(TreeNode root) {
//re:返回结果
List<List<Integer>> re = new ArrayList<>();
//调用遍历二叉树方法,在遍历的同时以X值进行了分类
//也就是说在这个方法之后,HashMap中已经有了数据
iterateTreeNode(root,0,0);
//得到所有的x
Object[] objects = map.keySet().toArray();
//在分类之后对X的值进行升序排序
Arrays.sort(objects);
//依照升序的x值遍历整个结果,并且对每个分类进行内部排序
for (Object key: objects
) {
//得到一类的数组
List<Entry> list = map.get(key);
//对该组数据进行排序
list.sort(new Comparator<Entry>() {
@Override
//排序逻辑
public int compare(Entry o1, Entry o2) {
//y不相等,直接以Y的降序进行排序,大的在前面
if (o1.y != o2.y)
return Integer.compare(o2.y,o1.y) ;
//如果y相等,那就依照value值进行排序,它是升序,小的在前面
else
return Integer.compare(o1.val,o2.val) ;
}
});
//经过上面的排序后,我们提取出val值,因为我们最后结果只需要val值
List<Integer> integerList = new ArrayList<>() ;
for (Entry entry:list){
//添加到integer数组中
integerList.add(entry.val) ;
}
把integerList加到结果值中
re.add(integerList) ;
}
//返回结果
return re ;
}
//遍历二叉树方法
private void iterateTreeNode(TreeNode node,int x, int y){
//递归出口
if (node == null)
return;
//如果有该类则直接把Entry加进去
if (map.containsKey(x)){
map.get(x).add(new Entry(node.val,y));
}
//没有该分类,即创建该分类,并加入对应的List
else
map.put(x,new java.util.ArrayList<>(Arrays.asList(new Entry(node.val,y)))) ;
//递归左子节点
iterateTreeNode(node.left,x-1,y-1);
//递归右子节点
iterateTreeNode(node.right,x+1,y-1);
}
//定义的内部类,用来辅助我们保存信息的
class Entry {
//结点值
int val;
//Y值
int y ;
//只有一个构造方法
public Entry(int val, int y) {
this.val = val;
this.y = y;
}
}
}
总的来说实现并不难。重点就在他的排序上而已。
肯定还有更加好的实现方法,期待大家的分享。