题目重点:海在右侧时,分别用后缀最大值和单调栈返回可见建筑下标。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 练习海在数组右侧;建筑仅在高度严格大于右侧所有建筑时可见,同高也遮挡。输入可含负高度,输出下标从小到大。
- 方向是合同的一部分,若海在左侧就镜像处理。建筑间距离不影响本题的高度遮挡判断;真实几何视角问题需要额外坐标。
解题路线
- 从右到左保留已看右侧的maximum。只有h>maximum时当前可见,记录下标并更新maximum;最后逆转输出恢复原顺序。
- 扫描不变式是maximum等于已处理后缀最大值,因此可见判断直接对应题意。用None初始化而非0,才能正确处理全部负高度和空数组。
- 若面试要求从左到右扫描,用下标栈保留尚未被遮挡的候选。当前高度≥栈顶高度时弹出栈顶,然后加入当前下标;同高必须弹出。
- 每个下标最多入栈与出栈一次,内层while总计O(N)。栈里的高度严格递减,其顺序天然是从左到右,结束时就是可见建筑。
手动走一遍
[4,2,3,1]可见[0,2,3];从左扫描遇3会移除2,遇1保留。对于[2,2]只有最右下标1可见;[-3,-2]也只有1可见。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def ocean_view_from_right(heights):
"""Ocean right; a building needs strictly greater height than all to right."""
maximum=None;visible=[]
for i in range(len(heights)-1,-1,-1):
if maximum is None or heights[i]>maximum:visible.append(i);maximum=heights[i]
return visible[::-1]
def ocean_view_left_to_right(heights):
"""Same right-ocean contract, scanning opposite way via decreasing stack."""
stack=[]
for i,height in enumerate(heights):
while stack and heights[stack[-1]]<=height:stack.pop()
stack.append(i)
return stack
复杂度
两种实现时间O(N)。右扫描除结果之外O(1)状态,结果逆转需要O(K)新列表;左扫描栈最坏O(N),最终栈即结果。若要求流式输出,左扫描早期候选可能被未来遮挡,不能立即确定。
易错点与追问
容易失分的边界
- 忽略同高遮挡,使用<弹栈导致错误保留。
- maximum初始化0,错误处理负高度。
- 把输出高度与输出下标混淆,重复高度会丢失身份。
继续深挖
- 如果海在两侧,分别计算两边可见集合并说明求并集还是交集。
- 若建筑高度支持更新,用区间最大值结构判断某建筑是否可见;输出全部可见仍受输出量下界约束。
