题目描述:
示例 1:

示例 2:

示例 3:

题目分析:
- 根节点的行列坐标(row, col)是(0,0)
- 任何节点其左右子结点的坐标满足 (row + 1, col - 1) 和 (row + 1, col + 1) 的规则
- 对于不同列数据需要保证从小到大输出
- 对于同一列中不同行的数据需要保证从小到大的顺序,例如:第一列第二行数据3,第一列第三行数据2,输出时应该是[3,2]
- 对于同一列同一行的数据,需要保证从小到大的顺序,例如第一列第三行数据5,第一列第三行数据2,输出时应该是[2,5]
思路:
- 先初始化一个哈希表map,key-列col,value-该列的所有数据,因为需要保证同一列下同一行的数据有序,因此我们需要知道同一列下哪些数据是同一行,所以map的value也是一个哈希表mapVal,key-行row,value-该行的数据。Map<Integer, Map<Integer, List<Integer>> map;
- 通过深度遍历构建出所有节点的坐标(row,col)
- 因为输出时,列从左往右,保持从小到大的顺序输出,因此map构建为有序map,保证列的顺序
- 因为同一列的数据输出是,行需要保证从上到下,从小到大的顺序输出,因此内存map构建为有序map,保证行的有序性
- 因为同一列同一行的数据需要保证从小到大的顺序输出,因此需要手动对list进行排序
- 遍历map依次输出,需要注意的是,同一列下不同行的数据需要整合到一个集合中进行输出。
代码实现:
class Solution {
public Map<Integer, Map<Integer, List<Integer>>> map = new TreeMap();
List<List<Integer>> result = new ArrayList();
public List<List<Integer>> verticalTraversal(TreeNode root) {
dfs(root, 0, 0);
// 获取列索引集合.
Set<Integer> set = map.keySet();
for (int i : set) {
// 从最小列开始输出
Map<Integer, List<Integer>> mapVal = map.get(i);
Set<Integer> setValKey = mapVal.keySet();
List<Integer> listVal = new ArrayList();
for (int j : setValKey) {
List<Integer> val = mapVal.get(j);
if (val.size() > 1) Collections.sort(val);
listVal.addAll(val);
}
result.add(listVal);
}
return result;
}
public void dfs(TreeNode node, int row, int col) {
if (node == null) {
return;
}
// 维护列关系.
Map<Integer, List<Integer>> mapVal = map.getOrDefault(col, new TreeMap<Integer, List<Integer>>());
// 维护同一列下行关系
List<Integer> list = mapVal.getOrDefault(row, new ArrayList<Integer>());
list.add(node.val);
mapVal.put(row, list);
map.put(col, mapVal);
dfs(node.left, row + 1, col - 1);
dfs(node.right, row + 1, col + 1);
}
}