算法-摩天大楼问题
这个题目是我在腾讯一面的时候遇到的,当时采用了暴力求解的算法,面试官也让过了,然而,我却挂在了二面。。。
看一下题目描述:
小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]+" ");
}
}