java-JD6 保卫方案
import java.util.Scanner;
import java.util.Stack;
/**
* JD6 保卫方案
* @author d3y1
*/
public class Main {
private static int N;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNext()){
solution(in);
}
}
/**
* 单调栈
* @param in
*/
private static void solution(Scanner in){
N = in.nextInt();
// 山峰高度数组
int[] heights = new int[N];
for (int i=0; i<N; i++) {
heights[i] = in.nextInt();
}
long result = getVisiblePairs(heights);
System.out.println(result);
}
/**
* 获取可互见对数: 相邻无重复高度
* @param heights
* @return
*/
public static int getVisiblePairsNoRepeat(int[] heights){
if (heights == null || N < 2){
return 0;
}
// 除去最高的两座山峰 每一座山峰都可以看见相邻2座山峰 2*(N-2)
// 最高的两座山峰之间是1对
// 2*(N-2)+1 = 2*N-3
return (N*2-3);
}
/**
* 获取可互见对数: 相邻有重复高度
* @param heights
* @return
*/
public static long getVisiblePairs(int[] heights){
if (N < 2){
return 0;
}
// 找到最高山峰索引 从该索引开始遍历
int maxHeightIndex = 0;
for (int i=0,size=N; i<size; i++) {
maxHeightIndex = heights[maxHeightIndex]>heights[i] ? maxHeightIndex:i;
}
// 单调栈 栈底到栈顶递减
Stack<Mountain> stack = new Stack<>();
stack.push(new Mountain(maxHeightIndex,1));
// 获得最高山峰的下一个索引
int next = getNextIndex(maxHeightIndex);
long count = 0;
Mountain curr;
while (next != maxHeightIndex){
// 单调栈循环
// 当加入的山峰高度会破坏栈的单调性时 弹出栈顶元素
while (!stack.isEmpty() && heights[stack.peek().index]<heights[next]){
curr = stack.pop();
// 往上配对数 + 当前相同高度配对数
count += curr.num + getCurrHeightPairs(curr.num);
if(!stack.isEmpty()){
// 往下配对数
count += curr.num;
}
}
if(!stack.isEmpty() && heights[stack.peek().index]==heights[next]){
// 山峰高度相同 则增加栈顶元素的num值
stack.peek().num++;
}else{
// 此时加入的山峰不会对栈的单调性造成影响 直接入栈
stack.push(new Mountain(next,1));
}
// 继续向后遍历
next = getNextIndex(next);
}
// 遍历完成后 将栈中剩余元素进行处理 可能依次经历3种阶段
// 阶段1 栈中剩余元素>2
while (stack.size() > 2){
curr = stack.pop();
// 环形 栈底元素也可看到当前元素(也可配对)
// 往下配对数 + 栈底配对数 + 当前相同高度配对数
count += 2*curr.num + getCurrHeightPairs(curr.num);
}
// 阶段2 栈中剩余元素=2
if (stack.size() == 2){
curr = stack.pop();
// 当前相同高度配对数 + 往下配对数 + 栈底配对数(栈底元素数量>1)
count += getCurrHeightPairs(curr.num) + (stack.peek().num==1 ? curr.num : 2*curr.num);
}
// 阶段3 栈中剩余元素=1
if (stack.size() == 1){
curr = stack.pop();
count += getCurrHeightPairs(curr.num);
}
return count;
}
/**
* 获取当前索引的下一个索引
* @param index
* @return
*/
public static int getNextIndex(int index){
return (index+1)%N;
}
/**
* 当前相同高度山峰配对数
* @param num
* @return
*/
public static long getCurrHeightPairs(long num){
return num*(num-1)/2;
}
static class Mountain{
// 山峰高度数组 索引
public int index;
// 相同高度山峰个数(相邻)
public int num;
public Mountain(int index,int num){
this.index = index;
this.num = num;
}
}
}