算法-摩天大楼问题

算法-摩天大楼问题

这个题目是我在腾讯一面的时候遇到的,当时采用了暴力求解的算法,面试官也让过了,然而,我却挂在了二面。。。

看一下题目描述:

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

暴力求解的方式比较简单,就是选定一个点,左右各一个指针,寻找到自己能看到的点进行统计即可,不过这样做时间复杂度有点高,题目要求是10000/座楼,显然暴力解会超时,另一种做法是使用单调栈,这样看过的楼就不必再去遍历了。
1、维护一个从左到右看的单调栈和一个从右到左看的单调栈。
2、维护单调栈对应的数组,存储单调栈到数组位置的大小,也就是能看到的大楼数量
3、合并两个数组,在对应位置+1(本楼也看得到)

    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        String[] height=in.nextLine().split(" ");
        int nums[]=new int[height.length];
        for (int i=0;i<height.length;i++){
            nums[i]=Integer.valueOf(height[i]);
        }
        helper(nums);
    }

    public static void helper(int[] height){
        int[]result=new int[height.length];
        int right[]=new int[height.length];
        int left[]=new int[height.length];
        Stack<Integer> leftStack=new Stack<>();
        Stack<Integer> rightStack=new Stack<>();
        //从左往右看
        for(int i=height.length-1;i>=0;i--){
            right[i]=rightStack.size();
            if(rightStack.isEmpty()){
                rightStack.push(height[i]);//右边第一个
            }else if(height[i]<rightStack.peek()){
                rightStack.push(height[i]);//如果比右边矮,就入栈,都能看到
            }else {
                while (rightStack.size()>0&&height[i]>=rightStack.peek()){
                    rightStack.pop();//如果突然有个高的,
                    // 那就把右边比这个矮的弹出。//保持单调栈
                }
                rightStack.push(height[i]);
            }
        }
        //从右往左看
        for(int i=0;i<height.length;i++){
            left[i]=leftStack.size();
            if(leftStack.isEmpty()){
                leftStack.push(height[i]);
            }else if(height[i]<leftStack.peek()){
                leftStack.push(height[i]);
            }else {
                while (leftStack.size()>0&&height[i]>=rightStack.peek()){
                    leftStack.pop();//维护单调栈
                }
                rightStack.push(height[i]);
            }
        }

        for (int i=0;i<result.length;i++){
            result[i]=left[i]+right[i]+1;
        }
        for(int i=0;i<result.length;i++){
            System.out.print(result[i]+" ");
        }
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值