数据结构--最大值减去最小值小于或等于num的子数组数量

给定数组arr和整数num, 共返回有多少个子数组满足如下情况:
max(arr[i..j]) - min(arr[i..j]) <= num
max(arr[i..j])表示子数组arr[i..j]中的最大值, min(arr[i..j])表示子数组arr[i.中的最小值。
【要求】
如果数组长度为N, 请实现时间复杂度为O(N)的解法。

 

 

子数组要求其中的元素是连续

解法一:暴力法  O(N³)  不可取

通过循环,找遍数组中所有的子数组,同时判断子数组中的值是否满足条件,如果满足,则加入到结果中

解法二:

①、如果一个子数组从L->R中,arr[max] - arr[min] <= num,那么在L->R范围内的子数组都符合要求

②、如果一个子数组从L->R中,arr[max] - arr[min] > num,那么以L->R为基础向外扩的子数组都不符合要求

做两个双端队列,一个是窗口内最大值,另外一个是窗口内最小值

1)、开始时L在数组最左端 0 位置,R从最左端开始向右扩,直到再扩充一个值就不符合要求时,R停止,设此时为 x 位置

则以0位置开始的子数组有 x + 1个(0,0~1,……0~x)  这些子数组是以0为起始位置符合要求的所有子数组个数

2)、L向右边移动一个位置,更新两个窗口内的结构,然后R试着继续向右扩,重复上面的,然后就能得到以1为起始位置符合要求的所有子数组个数

L每次向右移动一个位置,R就开始向右扩

 

/**
 * Created by Skye on 2018/5/3.
 * 给定数组arr和整数num, 共返回有多少个子数组满足如下情况:
 max(arr[i..j]) - min(arr[i..j]) <= num
 max(arr[i..j])表示子数组arr[i..j]中的最大值, min(arr[i..j])表示子数组arr[i.中的最小值。
 【要求】
 如果数组长度为N, 请实现时间复杂度为O(N)的解法。


 从当前位置 i 开始 采用双重循环, j 向后面开始扩充,采用两个队列,分别记录当前 i - j 的最大值和最小值
 当 arrays[maxList.peekLast()] - arrays[minList.peekLast()] > num 时不满足题意,
 则 j 停止扩充,然后计算从 i 到 j 共有多少个子数组  j - i 记录,
 并且判断当前位置 i 是否还在最大或最小队列中,如果存在,则弹出,因为 i 马上要过期了
 然后 i++ 继续扩充
 */
public class AllLessNumSubArray {

    public static int lessNumArray(int[] arrays, int num){
        if(arrays == null || arrays.length == 0) return 0;
        LinkedList<Integer> maxList = new LinkedList<>();
        LinkedList<Integer> minList = new LinkedList<>();
        int res = 0;
        int i = 0;
        int j = 0;
        while(i < arrays.length){
            while(j < arrays.length){
                while(!maxList.isEmpty() && arrays[maxList.peekLast()] <= arrays[j]){
                    maxList.pollLast();
                }
                while(!minList.isEmpty() && arrays[minList.peekLast()] >= arrays[j]){
                    minList.pollLast();
                }
                maxList.addLast(arrays[j]);
                minList.addLast(arrays[j]);
                j++;
                if(arrays[maxList.peekLast()] - arrays[minList.peekLast()] > num){
                    break;
                }
            }
            //判断是否超过了边值条件
            if(maxList.peekFirst() == i) maxList.pollFirst();
            if(minList.peekFirst() == i) minList.pollFirst();
            res += j - i;
            i++;
        }
        return res;
    }
}

 

  

 

转载于:https://www.cnblogs.com/SkyeAngel/p/8985801.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值