题目
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 256M,其他语言512M
小Q在周末的时候和他的小伙伴来到大城市逛街,
一条步行街上有很多高楼,共有n座高楼排成一行。
小Q从第一栋一直走到了最后一栋,小Q从来都没有
见到这么多的楼,所以他想知道他在每栋楼的位置处
能看到多少栋楼呢?(当前面的楼的高度
大于等于后面的楼时,后面的楼将被挡住)
输入例子1:
[5,3,8,3,2,5]
输出例子1:
[3,3,5,4,4,4]
例子说明1:
当小Q处于位置3时,他可以向前看到位置2,1处的楼,
向后看到位置4,6处的楼,加上第3栋楼,共可看到5栋楼。
当小Q处于位置4时,他可以向前看到位置3处的楼,
向后看到位置5,6处的楼,加上第4栋楼,共可看到4栋楼。
输入为一个数组,表示每一栋楼的高度w[i]
1<=数组长度<=100000;
1<=wi<=100000;
解答
package offer.tengxun;
import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;
public class Shopping
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
String line = in.nextLine();
line = line.replace("[", "");
line = line.replace("]", "");
in.close();
String[] arr = line.split(",");
int[] data = new int[arr.length];
for (int x = 0; x < arr.length; x++)
{
data[x] = Integer.parseInt(arr[x]);
}
int[] reslut = findBuilding3(data);
System.out.print("[");
for (int x=0;x<reslut.length;x++)
{
if(x==reslut.length-1)
{
System.out.print(reslut[x]);
}
else
{
System.out.print(reslut[x]+",");
}
}
System.out.print("]");
}
/*
* 这属于暴力解决了,遍历了两次这个数据,时间复杂度是n^2
* 题目数据量是10^5,运算量到达10^10,超时了
*/
public static int[] findBuilding1(int[] heights)
{
int[] data=new int[heights.length];
Arrays.fill(data, 1);
for(int x= 0;x<data.length;x++)
{
int index=x;
//先看左边
int max;
if(index>0)
{
data[x]++;
max=heights[x-1];
index--;
while(index>0)
{
if(heights[x-1]<heights[index-1] && max<heights[index-1])
{
data[x]++;
max=heights[index-1];
}
index--;
}
}
//然后看右边
index=x;
if(index<heights.length-1)
{
data[x]++;
index++;
max=heights[x+1];
while(index<heights.length-1)
{
if(heights[x+1]<heights[index+1]&& max<heights[index+1])
{
data[x]++;
max =heights[index+1];
}
index++;
}
}
}
return data;
}
public static int[] findBuilding2(int[] heights)
{
Stack<Integer> stack1 = new Stack<>();
int n = heights.length;
int[] res = new int[n];
Arrays.fill(res, 1); // 最起码能看到自己所在的这栋楼
// 首先向左边看
for (int i = 0; i < n - 1; i++)
{
// 只要当前楼大于等于前面遍历过的楼,
//就把前面的矮楼丢掉,因为我站在该楼右边是看不到的
while (!stack1.isEmpty() && heights[i] >= stack1.peek())
{
stack1.pop();
}
stack1.push(heights[i]);
/*
* 这里i+1才是核心,
* 因为我已经通过while循环把比当前楼矮的都去掉了,
* 所以栈里剩下的都比当前楼高
* 也就是说当我站在该楼的右边一栋楼,栈里的楼我都能看到
*/
res[i + 1] += stack1.size();
}
Stack<Integer> stack2 = new Stack<>();
for (int i = n - 1; i > 0; i--)
{ // 然后向右边看
while (!stack2.isEmpty() && heights[i] >= stack2.peek())
{
stack2.pop();
}
stack2.push(heights[i]);
res[i - 1] += stack2.size(); // 同理
}
return res;
}
public static int[] findBuilding3(int[] heights)
{
int[] result =new int[heights.length];
Arrays.fill(result, 1);//表示站在每一栋楼都能看到自己
//先看左边的楼
Stack<Integer> left =new Stack<Integer>();
for(int x=0;x<heights.length-1;x++)
{
while(!left.isEmpty() && left.peek()<=heights[x])
{
left.pop();
}
left.push(heights[x]);
result[x+1] += left.size();
}
//再看右边
Stack<Integer> right =new Stack<Integer>();
for(int x=heights.length-1;x>0;x--)
{
while(!right.isEmpty() && right.peek()<= heights[x])
{
right.pop();
}
right.push(heights[x]);
result[x-1] +=right.size();
}
return result;
}
}