城市天际线?
1、先看题
题目的表述并不清楚,而且已经开始铺陷阱了。所要求的四个方向,实际上两个足矣。
由于是看平面,从前看与从后看,从左看与从右看是完全一样的。
2、审题
善加使用手头的工具。对于二维的题,稍微画画图就能明确出思路。
本人是结合手边的小本本,才得出的思路。
题目略有些唬人,不过结合case还是能清楚地分析出其考点。
让我们来康康一些重点:
- 何为建筑轮廓?这个其实考验了一点大家的空间逻辑,即为一个角度看时,最高的一个大楼的高度。
- case里给足了提示,我们只需要从竖直和水平两个方向分析“天际线”。
- 如何变化建筑的高度,才能保持天际线不变呢?变化后的高度不超过该点所在的边或列上的最高点。
1 < grid.length = grid[0].length <= 50
。grid
数组是一个正方形,且边长最大为50.
3、思路
或许二维数组和长串不着边际的说明有些唬到打击。但实际上,这题在中等难度里也只能算是最为简单的题。
例子里给足了剧透。我们只用从横向和纵向两个纬度,来记录数组里的最大值即可。
于是我们需要初始化两个数组,数组长度和grid[][]
的边长一致(由于题目保证了grid
为正方形,故长宽一样)。
其次,遍历这个二维数组,对每一个点,比较并记录其所在的边和列上的最大值。
为保证变化后的天际线不变,每个点(建筑)能够提高到的高度为何呢?即为该点所在的边和列的最大值中,较低的一方。
想到这,答案应该就呼之欲出了。
4、开工!
public int maxIncreaseKeepingSkyline(int[][] grid) {
int[] x = new int[grid[0].length];
int[] y = new int[grid.length];
for (int i = 0; i < y.length; i++) {
for (int t = 0; t < x.length; t++) {
//遍历二维数组,计算纵向和横向的最大值
x[t] = Math.max(x[t], grid[i][t]);
y[i] = Math.max(y[i], grid[i][t]);
}
}
int inc = 0;
for (int i = 0; i < y.length; i++) {
for (int t = 0; t < x.length; t++) {
//比较该点纵向和横向的最大值,获取其较小的一方
int min = Math.min(x[t], y[i]);
//差值即为此点的建筑能够增加的高度
inc += min - grid[i][t];
}
}
return inc;
}
测试!提交!一气呵成!
让我不得不感慨今天果然还是一道简单题啊。
5、解读
两个数组,两重遍历。其作用和思路里描述的完全一致,这里也不用过多的解读什么的了。
而且关键语句我也写上了注释。
6、提交
虽然执行耗时仅1ms,但排名却落到了83%。
不知道是在什么地方浪费了些许时间,还是又有黑科技出现。
7、咀嚼
两遍两重循环,时间复杂度为O(N2),N为grid
的边长。
由于使用了两个数组,长度也分别为N,故空间复杂度为O(N)
如果真如我猜想有黑科技,辣么是仅遍历了一遍?还是说能有时间复杂度为O(logN)的二次遍历?
8、他人的智慧
抱着以上的猜想,我惯例翻了翻题解。
却并没有什么收获。
从官解到比较热门的各种大牛的题解里,都是类似的解法。
暴力贪心,简单明了的思路。并没有看到黑科技。
但还是放出一些大牛的题解,供大家学习
大牛们不仅写了分析,还画了图,更加明了地讲解了题目。
让社畜画图是不可能的,这辈子都不可能的。除非遇上什么文字实在无法表述的题再说吧。但文字都说不清了,我还可以鸽啊
9、总结
今天的中等题完全没有中等题的面子。能够收获的大概就只有巩固基础了。
总之今天好歹是周一,各位社畜们想必都有自己的砖要搬,辣么就不多写些什么,各位共勉吧。
弔!我唔想返工啊!