求大楼整体轮廓线的数组

问题描述:

给定一个 N×3 的矩阵 matrix,对于每一个长度为 3 的小数组 arr,都表示一个大楼的三个数
据。arr[0]表示大楼的左边界,arr[1]表示大楼的右边界,arr[2]表示大楼的高度(一定大于 0)。
每座大楼的地基都在 X 轴上,大楼之间可能会有重叠,请返回整体的轮廓线数组。

样例:

输入:

matrix = {
{2,5,6},
{1,7,4},
{4,6,7},
{3,6,5},
{10,13,2},
{9,11,3},
{12,14,4},
{10,12,5}
}

 输出:

{{1,2,4},
{2,4,6},
{4,6,7},
{6,7,4},
{9,10,3},
{10,12,5},
{12,14,4}}

 

求解思路:

  1. 首先将每个输入的数组转换成两个数组,一个表示左端点上升了多大高度,一个表示右端点下降了多少高度。用true表示上升,false表示下降,如{2,5,6}可以改写成{2,true,6}{5,false,6}
  2. 将输入的数组转换完毕后,按照规定的比较规则进行排序,比较规则为:
    • 按照x坐标的大小排序,x坐标小的排在x坐标大的前面
    • 如果x坐标相等,看该数组是上升还是下降,上升在前下降在后
  3. 准备两个有序表,这里采用TreeMap代替(底层为红黑树),一个(map1)存储高度和对应的数量,一个(map2)存储x坐标和对应的最大高度
  4. 开始遍历处理完后的数组
    • 如果当前数组对于加入操作,则先查看map1中是否有这个高度,有则对应数量+1,否则创建记录、
    • 更新map2中的记录,如果map2中没记录当前x对应的高度,则创建新纪录;如果创建过当前x的高度,则更新其高度。高度为map1中的最后一个记录。
  5. 根据map2生成对应大楼外轮廓图

Coding

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;

public class Problem01_BuildingOutline {

	// 描述高度变化的对象
	public static class Node {
		public int x; // x轴上的值
		public boolean isAdd;// true为加入,false为删除
		public int h; // 高度

		public Node(int x, boolean isAdd, int h) {
			this.x = x;
			this.isAdd = isAdd;
			this.h = h;
		}
	}

	// 排序的比较策略
	// 1,第一个维度的x值从小到大。
	// 2,如果第一个维度的值相等,看第二个维度的值,“加入”排在前,“删除”排在后
	// 3,如果两个对象第一维度和第二个维度的值都相等,则认为两个对象相等,谁在前都行。
	public static class NodeComparator implements Comparator<Node> {
		@Override
		public int compare(Node o1, Node o2) {
			if (o1.x != o2.x) {
				return o1.x - o2.x;
			}
			if (o1.isAdd != o2.isAdd) {
				return o1.isAdd ? -1 : 1;
			}
			return 0;
		}
	}

	// 全部流程的主方法
	public static List<List<Integer>> buildingOutline(int[][] matrix) {
		Node[] nodes = new Node[matrix.length * 2];
		// 每一个大楼轮廓数组,产生两个描述高度变化的对象
		for (int i = 0; i < matrix.length; i++) {
			nodes[i * 2] = new Node(matrix[i][0], true, matrix[i][2]);
			nodes[i * 2 + 1] = new Node(matrix[i][1], false, matrix[i][2]);
		}

		// 把描述高度变化的对象数组,按照规定的排序策略排序
		Arrays.sort(nodes, new NodeComparator());

		// TreeMap就是java中的红黑树结构,直接当作有序表来使用
		TreeMap<Integer, Integer> mapHeightTimes = new TreeMap<>();
		TreeMap<Integer, Integer> mapXvalueHeight = new TreeMap<>();
		for (int i = 0; i < nodes.length; i++) {
			if (nodes[i].isAdd) { // 如果当前是加入操作
				if (!mapHeightTimes.containsKey(nodes[i].h)) { // 没有出现的高度直接新加记录
					mapHeightTimes.put(nodes[i].h, 1);
				} else { // 之前出现的高度,次数加1即可
					mapHeightTimes.put(nodes[i].h,
							mapHeightTimes.get(nodes[i].h) + 1);
				}
			} else { // 如果当前是删除操作
				if (mapHeightTimes.get(nodes[i].h) == 1) { // 如果当前的高度出现次数为1,直接删除记录
					mapHeightTimes.remove(nodes[i].h);
				} else { // 如果当前的高度出现次数大于1,次数减1即可
					mapHeightTimes.put(nodes[i].h,
							mapHeightTimes.get(nodes[i].h) - 1);
				}
			}

			// 根据mapHeightTimes中的最大高度,设置mapXvalueHeight表
			if (mapHeightTimes.isEmpty()) { // 如果mapHeightTimes为空,说明最大高度为0
				mapXvalueHeight.put(nodes[i].x, 0);
			} else { // 如果mapHeightTimes不为空,通过mapHeightTimes.lastKey()取得最大高度
				mapXvalueHeight.put(nodes[i].x, mapHeightTimes.lastKey());
			}
		}
		// res为结果数组,每一个List<Integer>代表一个轮廓线,有开始位置,结束位置,高度,一共三个信息
		List<List<Integer>> res = new ArrayList<>();
		// 一个新轮廓线的开始位置
		int start = 0;
		// 之前的最大高度
		int preHeight = 0;
		// 根据mapXvalueHeight生成res数组
		for (Entry<Integer, Integer> entry : mapXvalueHeight.entrySet()) {
			// 当前位置
			int curX = entry.getKey();
			// 当前最大高度
			int curMaxHeight = entry.getValue();
			if (preHeight != curMaxHeight) { // 之前最大高度和当前最大高度不一样时
				if (preHeight != 0) {
					res.add(new ArrayList<>(Arrays.asList(start, curX, preHeight)));
				}
				start = curX;
				preHeight = curMaxHeight;
			}
		}
		return res;
	}

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值