腾讯校招笔试题

387 阅读3分钟

题目描述:

小Q在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有n座高楼排成一行。小Q从第一栋一直走到了最后一栋,小Q从来都没有见到这么多的楼,所以他想知道他在每栋楼的位置处能看到多少栋楼呢?(当前面的楼的高度大于等于后面的楼时,后面的楼将被挡住)

输入第一行将包含一个数字n,代表楼的栋数,接下来的一行将包含n个数字wi(1<=i<=n),代表每一栋楼的高度。

样例输出

6
5 3 8 3 2 5

样例输出:

3 3 5 4 4 4

图解题目:

如图即是样例给出的五栋楼(是不是清晰多了)

image.png

题目的意思是什么呢?

当你站在下标为0的楼层时,你可以看到几栋楼呢?

首先你可以看到脚下的自己(废话),然后向右看(左边没有)肯定能看到1号楼,也能看到2号楼,但是3,4,5号楼就看不见了,因为都被2号楼挡住了

值得注意的是

当你站在最高层2号楼的时候,也不是所有楼层都能看见哦;4号楼你就看不见 ,因为被三号楼挡住了(此处不是很符合现实)

解题思路:

以中间3号楼为例,如果从最左0号楼到自己 一直是递减的那么 从0号楼到自己这一路上的楼层都能看见,但是一旦有一个比前面楼层高的 那么肯定会遮挡住,如2号楼就会遮挡住0,1号楼,到最后只能看见2号楼;

同理如果三号楼最右的5号楼到自己 一直是递减的话,那么一路的楼自己都能看到

有了这个思路,我们就不难理解使用栈这个想法了。我们利用两个栈,来分别找到某栋楼左面能看到的楼层,和右面能看到的楼层;然后用一个数组分别加上就好了;

如:先把0加入栈,此时栈中1个元素,那么1号楼向左看就只能看到一栋楼(不包括自己的情况下);

然后看1号楼,1号楼的高度小于栈顶,所以加入栈,栈中此时是53,所以2号楼向左看肯定能看到两栋楼;

然后碰到了2号楼,2号楼的高度大于栈顶元素3(3号楼肯定看不见1号楼了),所以我们删除栈顶元素3,然后栈顶元素5还是小于2号楼高度8,所以再次删除栈顶元素,然后栈中加入8,此时栈中只有8,3号楼向左只能看见一栋楼;

向右看也是同理,接下来让我们看看代码(有注释);

public int[] findBuild(int[] heights) {//heights是楼的高度数组(例:5,3,8,3,2,5)
    Stack<Integer> leftBuild = new Stack();//描述的是第i栋楼,向左能看到的楼的数量
    Stack<Integer> rightBuild = new Stack();//描述的是第i栋楼,向右能看到的楼的数量
    int n = heights.length;//一共有多少栋楼
    int[] res = new int[n];//结果,第i栋楼能看到的楼的总数量(左+右+自身)
    Arrays.fill(res,1);//自己能看见自己
    //从左向右,找到第i+1栋楼向左可以看见的楼的个数
    for(int i = 0; i < n - 1; i++) {
        //如果为空的话直接加栈里就行,while循环将小于等于heights[i]的都删除(都档上了)
        while (!leftBuild.isEmpty() && heights[i] >= leftBuild.peek()) {
            leftBuild.pop();
        }
        //第i + 1栋楼   左面能看到的楼的数量;
        res[i + 1] += leftBuild.size();//注意是累加的
    }
    //从右向左,找到第i-1栋楼向右可以看见的楼的个数
    for (int i = n - 1; i > 0; i--) {
        while (!rightBuild && heights[i] > rightBuild.peek()) {
            rightBuild.pop();
        }
        rightBuild.push(heights[i]);
        res[i - 1] += rightBuild.size();
    }
    return res;
}