最大值减去最小值小于等于num的子数组数量-------Java从0开始学习系列之路(10)

前言---

最后一篇补完,我就要回宿舍了,在这美好的中秋之夜,吃火锅了,加油,CCSGTC!!!

最大值减去最小值小于或等于num的子数组的数量

题目:

给定数组arr和整数num,返回有多少个子数组满足max(array[i...j]) - min(array[i...j]) <=num.

max(array[i...j])表示array[i...j]中的最大值:

min(array[i...j])表示array[i,.j]中的最小值

要求实现的复杂度为O(N)。

分析:

这道题如果暴力的话,是很简单的,也就是O(n^3),但是复杂度太差了,要是n的数值大一点,就很容易TLE了。
先给出两个结论:
(1)

如果当前所在的数组Array[j...k]满足 max - min <=num;   那么以这个数组的所有子数组Array[l, r]
( j <=l <= r <=k)也都满足max - min <= num;
证明也是很容易理解的:
其任意的子数组的max一定<=其自身的max,任意子数组的min一定>=其自身的min ,所以该结论成立。

(2)
如果一个数组Array[j...k]不满足 max - min <=num;那么任何包含该数组的数组来说,也一定不满足max - min <=num;
证明同第一个结论一样易于理解:
设包含Array[j...k]的数组为Array[l ...r](l <= j <= k <= r),显然,Array[l...r]的max一定>=Array[j...k],
Array[l...r]的min一定<=Array[j...k]。

这两个结论,大家一定要先理解。


这个题目的优秀做法是,通过维护qmax的双端单调递减队列,来求子数组的最大值;通过维护qmin的双端单调递减队列,来
求子数组的最小值。
原理是:通过求以Array[i]( 0<=i<=length-1)为起点的满足条件的子数组数量,每个起点对应的答案加起来就是总数量了。

这边就是要注意一个下标i指针移动,最大值和最小值可能会改变,此时要弹出队列的左端点,跟本博客中“滑动窗口求最值"原理一样,读者不理解可去看看,这边不再细说。

附代码(Java)

package code_180;

import java.util.*;
public class subArrayNum {


	LinkedList<Integer>qmax ;//基于LinkedList实现的双端队列。用于维护最大值
	LinkedList<Integer>qmin;//用于维护当前数组的最小值
	
	subArrayNum(){
		
		qmax = new LinkedList<Integer>();
		qmin = new LinkedList<Integer>();
	}
	
	public int getMax(  int []array,   int num ) {
		
		int l =  0 ,r = 0;
		int ans = 0;
		
		while(l < array.length ) {   
			
			
		 while( r < array.length) {
			    	
	
				while( !qmax.isEmpty()&& array[r] >= array[qmax.peekLast()]) {
				
					qmax.pollLast();
				}
			    qmax.addLast(r);
			
			
				while( !qmin.isEmpty() && array[r] <= array[qmin.peekLast()]) {
				
					qmin.pollLast();
				}
				qmin.addLast(r);
				
				if( array[qmax.peekFirst()] - array[qmin.peekFirst()] > num )
					break;
				
				r++;
					
		  }
		 
				
		        ans += r-l;
				if(qmax.peekFirst() == l)
					qmax.pollFirst();
				
				if(qmin.peekFirst() == l )
					qmin.pollFirst();

				l++;
				//System.out.println(ans);
				//System.out.println("Ok");
			

	}
			
	
		
		return ans;
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		int array[] = {3,2,5,1,4,7,8,6};
		
		subArrayNum myQueue  = new subArrayNum();
		
		System.out.println( myQueue.getMax(array, 4));
		
		

  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值