题解 | #最大最小#

最大最小

http://www.nowcoder.com/practice/62dcedffb0694a0baff9e9cee0abc86d

题意整理

  • 给定一个数组。
  • 求所有的区间中,满足区间最大值大于等于最小值对应的区间个数。

方法一(暴力)

1.解题思路

  • 先确定左端点,然后遍历所有的右端点。
  • 每次记录最大值和最小值,只要最大值大于等于最小值,则结束内循环。将满足条件的区间数加入到结果变量。
  • 直到确定完所有的左端点。

动图展示:
图片说明

2.代码实现

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型一维数组 array
     * @return long长整型
     */
    public long MaxMin (int[] array) {
        int n=array.length;
        //初始化区间计数变量
        long cnt=0L;
        for(int i=0;i<n;i++){
            //记录最小值和最大值
            int min=array[i];
            int max=array[i];
            for(int j=i+1;j<n;j++){
                min=Math.min(min,array[j]);
                max=Math.max(max,array[j]);
                //如果当前最大值大于等于最小值两倍
                if(max>=min*2){
                    //左端点为i,右端点为j到n-1对应的区间都是合法的
                    cnt+=n-j;
                    break;
                }
            }
        }
        return cnt;
    }
}

3.复杂度分析

  • 时间复杂度:总共两层循环,最多遍历次,所以时间复杂度为
  • 空间复杂度:需要额外常数级别的空间,所以空间复杂度为

方法二(单调栈+二分)

1.解题思路

  • 首先初始化两个单调栈,一个记录递增序列,一个记录递减序列。
  • 从后往前遍历原数组,所以单调栈记录的值一定在当前数字对应下标之后的位置。然后找到右边第一个小于等于其二分之一的数对应的下标、右边第一个大于等于其两倍的数对应的下标,记录到对应的数组。
  • 再次从后往前遍历原数组,以当前点(下标i处的数字)为左端点,右端点为对应的区间都是合法的,加上对应的区间数到结果数组。然后每次跟新最大的合法区间,保证当前的合法区间是最大的。

2.代码实现

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型一维数组 array
     * @return long长整型
     */
    public long MaxMin (int[] array) {
        int n=array.length;
        long cnt=0;
        //维护一个递增序列
        ArrayList<int[]> asc=new ArrayList<>();
        //维护一个递减序列
        ArrayList<int[]> desc=new ArrayList<>();
        //记录右边第一个大于等于当前数字两倍的数对应的下标
        int[] maxPos=new int[n];
        //记录右边第一个小于等于当前数字二分之一的数对应的下标
        int[] minPos=new int[n];
        for(int i=n-1;i>=0;i--){
            while(!asc.isEmpty()&&asc.get(asc.size()-1)[0]>array[i]){
                asc.remove(asc.size()-1);
            }
            //二分查找对应下标
            int pos=binarySearch1(asc,array[i]);
            if(pos==-1){
                minPos[i]=n;
            }
            else{
                minPos[i]=asc.get(pos)[1];
            }
            //添加当前元素及其下标
            asc.add(new int[]{array[i],i});
        }

        for(int i=n-1;i>=0;i--){
            while(!desc.isEmpty()&&desc.get(desc.size()-1)[0]<array[i]){
                desc.remove(desc.size()-1);
            }
            //二分查找对应下标
            int pos=binarySearch2(desc,array[i]);
            if(pos==-1){
                maxPos[i]=n;
            }
            else{
                maxPos[i]=desc.get(pos)[1];
            }
            //添加当前元素及其下标
            desc.add(new int[]{array[i],i});
        }

        //记录当前下标为左端点时,对应的合法区间数
        int[] b=new int[n];
        for(int i=n-1;i>=0;i--){
            //左端点为i,右端点为min(minPos[i],maxPos[i])到n-1对应的区间都是合法的
            b[i]=n-Math.min(minPos[i],maxPos[i]);
            //每次取最大的区间数作为合法区间数
            if(i!=n-1){
                b[i]=Math.max(b[i],b[i+1]);
            }
            cnt+=b[i];
        }
        return cnt;
    }

    //找到target右边第一个小于等于其二分之一的数对应的下标
    private int binarySearch1(ArrayList<int[]> asc,int target){
        int l=-1,r=asc.size()-1;
        while(l<r){
            //上取整,防止死循环
            int mid=l+(r-l+1)/2;
            if(asc.get(mid)[0]*2<=target){
                l=mid;
            }
            else{
                r=mid-1;
            }
        }
        return l;
    }

    //找到target右边第一个大于等于其两倍的数对应的下标
    private int binarySearch2(ArrayList<int[]> desc,int target){
        int l=-1,r=desc.size()-1;
        while(l<r){
            //上取整,防止死循环
            int mid=l+(r-l+1)/2;
            if(desc.get(mid)[0]>=2*target){
                l=mid;
            }
            else{
                r=mid-1;
            }
        }
        return l;
    }
}

3.复杂度分析

  • 时间复杂度:二分查找的时间复杂度为,二分外面还嵌套一层循环,所以时间复杂度为
  • 空间复杂度:需要额外大小为n的单调栈以及各种用于中间状态记录的数组,所以空间复杂度为
xqxls的题解 文章被收录于专栏

牛客题解

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
正在热议
更多
# 一张图晒出你司的标语 #
4249次浏览 75人参与
# AI面会问哪些问题? #
27474次浏览 550人参与
# 厦门银行科技岗值不值得投 #
7915次浏览 188人参与
# 你的实习产出是真实的还是包装的? #
20012次浏览 342人参与
# 找AI工作可以去哪些公司? #
8924次浏览 230人参与
# 春招至今,你的战绩如何? #
64347次浏览 575人参与
# 开放七大实习专项,百度暑期实习值得冲吗 #
15051次浏览 221人参与
# 从事AI岗需要掌握哪些技术栈? #
8776次浏览 299人参与
# 你做过最难的笔试是哪家公司 #
33017次浏览 229人参与
# 中国电信笔试 #
31886次浏览 292人参与
# 投递几十家公司,到现在0offer,大家都一样吗 #
340689次浏览 2173人参与
# 哪些公司真双非友好? #
69551次浏览 289人参与
# 阿里笔试 #
178341次浏览 1314人参与
# 机械人避雷的岗位/公司 #
62673次浏览 393人参与
# 第一份工作一定要去大厂吗 #
14380次浏览 122人参与
# 金三银四,你的春招进行到哪个阶段了? #
22046次浏览 280人参与
# 为了减少AI幻觉,你注入过哪些设定? #
26220次浏览 310人参与
# 沪漂/北漂你觉得哪个更苦? #
9741次浏览 193人参与
# HR最不可信的一句话是__ #
6145次浏览 113人参与
# 应届生第一份工资要多少合适 #
20663次浏览 86人参与
# AI时代,哪个岗位还有“活路” #
11407次浏览 339人参与
# 春招你拿到offer了吗 #
831056次浏览 9986人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务