zoukankan      html  css  js  c++  java
  • 一道面试题(单调栈)

    不含负数,可能含有相同数值的山峰数组(环形)
    山峰A和山峰B能互相看见的条件是:
    1、AB是不同的山且相邻
    2、AB是不同的山,且A到B的两个方向上至少有一个方向上没有比A高的山峰
     
      分析:本题有两种情况
          第一种是山峰都是不同高度的,这样的话本题就可以有O(1)的解,山峰如果是不同高度,那么当山峰数量大于等于2的时候,必有一个最高山峰,一个次高山峰
      所以,假设山峰数量为n,则剩下的每个山峰都可以在顺时针方向找到第一个高于它的山峰,逆时针找到第一个高于它的山峰,所以剩下的山峰对就是2 * (n - 2),最后我们要算上次高和最高山峰组成的一对
      那么总共山峰对就是2 * n - 3对。
          第二种情况就是下面代码所示,可以有重复高度的山峰,我们沿着一个方向遍历山峰,维护一个单调栈,从栈低到栈顶为高度上升的,注意这里最重要的一点是,首先遍历山峰高度数组,
      找到一个最高山峰为起点,将它压入栈中,这样做会保证栈底一定会有一个比之后山峰高的山峰,每次遇到低于栈顶山峰的山峰直接压入栈中,遇到高于栈顶的山峰,此时栈顶的山峰就可以计算形成的山峰对,
      因为是可重复高度的,所以还要计算有几个相同高度自身形成的山峰对,是个组合数Cn2,这样一直到遍历一圈回到初始的最大山峰索引结束,结束后栈内若仍有元素,就一直弹出继续清算山峰对,直到栈为空。
    public class Mountains {
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            sc.nextLine();
            String[] s = sc.nextLine().split(" ");
            int[] arr = new int[n];
            for(int i = 0; i < n; i++) {
                arr[i] = Integer.parseInt(s[i]);
            }
            System.out.println(getAllPair(arr));
        }
        public static int getAllPair(int[] arr) {
            if(arr == null || arr.length < 2) return 0;
            int size = arr.length;
            int maxIndex = 0;
            for(int i =  1; i < size; i++) {
                if(arr[maxIndex] < arr[i]) maxIndex = i;
            }
            Stack<Record> stack = new Stack<>();
            stack.push(new Record(arr[maxIndex]));
            int res = 0, curIndex = nextIndex(maxIndex, size);
            while(maxIndex != curIndex) {
                while(arr[curIndex] > stack.peek().val) {
                    int k = stack.pop().times;
                    res += k * 2 + getInternal(k);
                }
                if(arr[curIndex] == stack.peek().val) {
                    stack.peek().times++;
                } else {
                    stack.push(new Record(arr[curIndex]));
                }
                curIndex = nextIndex(curIndex, size);
            }
            while(stack.size() > 2) {
                int k = stack.pop().times;
                res += getInternal(k) + k * 2;
            }
            if(stack.size() == 2) {
                int k = stack.pop().times;
                res += getInternal(k) + stack.peek().times == 1 ? k : k * 2;
            }
            res += getInternal(stack.pop().times);
            return res;
        }
    
        public static int getInternal(int n) {
            return n == 1 ? 0 : n * (n-1) / 2;
        }
        public static int nextIndex(int i, int size) {
            return i < size - 1 ? i + 1 : 0;
        }
    
    }
    
    class Record {
        int val, times;
        public Record(int val) {
            this.val = val;
            times = 1;
        }
    }
  • 相关阅读:
    NOIP201310华容道
    NOIP201110观光公交
    markdown
    【NOIP2016】愤怒的小鸟
    【NOIP2016】组合数问题
    [TJOI2019]唱,跳,rap,篮球(生成函数,组合数学,NTT)
    CF1217E Sum Queries? (线段树)
    CF1178F Short/Long Colorful Strip(DP)
    ZROI 暑期高端峰会2019 总结
    [HNOI2012]集合选数(构造,状态压缩,DP)
  • 原文地址:https://www.cnblogs.com/yonezu/p/13261096.html
Copyright © 2011-2022 走看看