• 一道面试题(单调栈)


    不含负数,可能含有相同数值的山峰数组(环形)
    山峰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;
        }
    }
  • 相关阅读:
    解决 搭建Jekins过程中 启动Tomcat的java.net.UnknownHostException异常
    射手和农场主
    java 和 JS(javaScript)中的反斜杠正则转义
    分享修改密码的SharePoint Web part: ITaCS Change Password web part
    分享微软官方Demo用的SharePoint 2010, Exchange 2010, Lync 2010虚拟机
    Office 365 的公共网站的一些限制及解决的办法
    SharePoint 2013 关闭 customErrors
    安装 KB2844286 导致SharePoint 2010 XSLT web part 显示出现错误
    安装Office Web Apps Server 2013 – KB2592525安装失败
    如何将hyper-v虚拟机转换成vmware的虚拟机- 转换SharePoint 2010 Information Worker Demonstration and Evaluation Virtual Machine (SP1)
  • 原文地址:https://www.cnblogs.com/yonezu/p/13261096.html
Copyright © 2020-2023  润新知