城市天际线问题:用单调栈解决建筑可见性难题

0 阅读2分钟

城市天际线可见建筑数量 —— 核心知识点(大二Java刷题笔记)

  1. 题目是什么?

从左往右看一排高低不同的建筑(高度数组), 求每一栋建筑,能向左看到多少栋楼。 被挡住的看不见,只有比它高的建筑才能挡住它。

IMG_20260317_210415.jpg
  1. 本题本质

寻找每个元素左边第一个比它大的数 英文:Previous Greater Element

这是单调栈最经典的应用场景。

 

  1. 为什么要用「单调栈」?
  • 普通遍历:O(n²),效率低 ​
  • 单调栈:O(n),每个元素只入栈、出栈一次 ​
  • 栈里只存下标,不存高度,方便计算距离

 

  1. 栈的规则(最重要)

栈内保持: 从栈底到栈顶,高度单调递减

  • 遇到更高的楼:前面矮的全都没用了,弹出 ​
  • 遇到更矮的楼:直接入栈,继续维护递减

 

  1. 核心计算逻辑

对第 i 栋楼:

1. 把所有比它矮或相等的栈顶弹出 ​ 2. 弹出后: ​

  • 栈空 → 能看到 i+1 栋 ​
  • 栈不空 → 能看到 i - 栈顶下标 栋 ​ 3. 把当前下标压入栈

 

  1. 本题最容易踩的 4 个坑

1. top 先++ 还是先赋值 ​

  • 必须:先判断 → 再 top++ → 再赋值 ​ 2. 栈满判断错误 ​
  • 满: top >= stack.length - 1  ​ 3. 栈空时直接 peek / pop ​
  • 必须先判断  isEmpty()  ​ 4. 把 >= 写成 > ​
  • 等高也要挡住,必须用  >= 

 

  1. 一句话总结

矮的踢走,高的留下,算完距离再入栈。 左边第一个更大元素,用单调栈一遍过

8.完整代码展示【这里就懒得拆分了,直接上全部代码】

public class CityStack {
    private static int[] heights;//城市建筑高度
    private static int size;//栈内元素个数
    private  int top;//定义栈顶指针
    private static int cnt;//统计可见建筑的数量
    private  int[] stack;

    public CityStack() {
        this.stack = new int[10];
        size = 0;
        top = -1;
        cnt = 0;
    }

    //push方法
    public  void push(int index) {
        if (size == 6) {
            System.out.println("Stack is full");
            return;
        }
        if(top >= stack.length-1) throw new RuntimeException("Stack is full");
        top++;
        stack[top] = index;//top属于栈,index属于高度数组的下标,两者不同才能赋值
        size++;
    }

    //pop方法
    public  int pop() {//pop本身是弹出栈顶元素,不用传入参数
        if (top == -1) {
            System.out.println("Stack is empty");
           throw new RuntimeException("Stack is empty");
        } else {
            return stack[top--];
        }
    }

    public static void main(String[] args) {
        int[] heights = {10, 6, 8, 5, 11, 9};
        CityStack cs = new CityStack();
        System.out.println(Arrays.toString(heights));
        int[] ans = new int[heights.length];
        for (int i = heights.length-1;i >= 0 ; i--) {
            int cnt = 0;
            while(cs.top != -1&&heights[i] >= heights[cs.stack[cs.top]]) {
            //这里是拿高度数组里面的高度与栈内已存入的建筑高度比较
                cs.pop();
                cnt++;
            }
            ans[i] = cnt + 1;
            cs.push(i);
        }
        System.out.println(Arrays.toString(ans));
    }
}