• 绝对差不超过限制的最长连续子数组 RMQ+二分答案


    感谢https://www.cnblogs.com/yyxayz/p/4109390.html


    思路,首先暴力肯定超时了,那么就要想办法来优化,当然是百度了
    首先很显然的是,如果一个区间的最大值和最小值分别是mi和ma
    那么如果ma-mi<=limits,那么这个区间就是合法的区间
    所以我们就要找一个方法快速的求区间的最大值与最小值
    这当然可以用线段树来做,但是线段树写起来麻烦,此时祭出
    大杀器,rmq,可以通过o(nlogn)复杂度来预处理,o(1)复杂度
    查询区间的最值,有了这个之后,就可以二分答案,o(nlogn)来求解了
    但是感觉双指针在这里应该也能做到,而且是o(n)但是影响不大了


    RMQ的基本思想

    RMQ的基本思想就是对区间的进行拆分,来利用动态规划的方法求解子问题
    利用一个dp数组,其中dp[i][j]表示以i开始,长度为2^j次方的数组的最值
    可以知道,这个数组是可以覆盖任何一个子区间的,因为数组的长度为n,那么
    n必然可以拆分成2^k这种的相加形式,而且因为我们查询的时候,区间可以覆盖
    所以一次查询只需要访问两次数组。而前面的预处理过程则由,大区间有小区间
    覆盖来求得,方便快捷


    int maxn[100005][20];
    int minn[100005][20];
    class Solution {
    public:
        int longestSubarray(vector<int>& nums, int limit) {
            //二分答案,求最大值与最小值
            nums.insert(nums.begin(),0);
            getbestarr(nums.size()-1,nums);
            int ma = nums.size()-1;
            int mi=1;
            int mid=0;
            int ans = 0;
            int len=nums.size()-1;
            while(mi<=ma){
                bool flag = false;
                mid = (ma+mi)>>1;
                for(int i=1; i<=len-mid+1;i++){
                    if(abs(query(i,i+mid-1,0)-query(i,i+mid-1,1))<=limit){
                        flag=true;
                        ans = mid;
                        break;
                    }
                }
                if(flag){
                    mi=mid+1;
                }
                else{
                    ma=mid-1;
                }
            }
            return ans;
        }
        void ini(){
            for(int i=0; i<100005; i++){
                for(int j=0; j<20; j++)
                      minn[i][0]= maxn[i][0] = 0;  
            }
        }
        void getbestarr(int n,vector<int>&arr)//n为给定的数组的长度  
        {  
            ini();
             int tem = (int)floor(log2((double)n));
           for(int i=1;i<=n;i++)  
                minn[i][0]= maxn[i][0] = arr[i];  
            for(int j=1;j<=tem;j++) //下标从1开始  
                 for(int i=1;i+(1<<j)-1<=n;i++)  
               {  
                     maxn[i][j] = max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);  //最大值  
                     minn[i][j] = min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);  //最小值  
                }  
        }
        int query(int a,int b,bool getwhat)//getwhat表示你是想取最大还是最小  
        {  
           int k = log2(b-a+1);  
           if(getwhat)  
               return max(maxn[a][k],maxn[b-(1<<k)+1][k]);  
           else  
                 return min(minn[a][k],minn[b-(1<<k)+1][k]);  
        }
    };
    
  • 相关阅读:
    【转】Odoo开发之:工作流 workflow
    【转】Odoo:基本字段类型
    【转】odoo 10的企业微信发送程序介绍
    Installing python-ldap in Ubuntu
    Odoo8中安装新模块找不到的问题
    mybatis缓存
    ThreadPoolExecutor线程池进阶使用
    使用Dubbo实现RPC调用
    java静态代理模式
    java四种线程池
  • 原文地址:https://www.cnblogs.com/Crossea/p/12821400.html
Copyright © 2020-2023  润新知