数列 - Sequence - Indexed Tree

数列

测试用例总数:40 个用例,1.5 秒 (C/C++),2 秒 (JAVA)

当前有一组包含N个数字的数列。当从数列中选取几个连续的数字时,想在这些选择的数字中创建最小值和最大值差为K的子数列。请求出最大值和最小值差为K的子数列中长度为最短的情况。

 

下面案例是从包含10个数的数列中找出K为10的子数列。
为方便起见,数列的第一个数字开始定义为 index 1, index 2, …, index 10

数列 - Sequence - Indexed Tree

 

 

当选择Index 1到5时,最大值为11,最小值为1,满足差值为K的要求,并且长度为 5。当选择Index 5到8时,最大值为21,最小值为11,满足差值为K的要求,并且长度为4。这是满足条件的最短的子数列。

给出数组大小N和最大值与最小值之差K,以及数组的值时,请找出可选择的最短长度子数列和长度最短的子数列个数。如果不存在这种情况,则输出 -1。

 

[限制条件]

1.数字个数N为介于1到100,000之间的整数。

2.各数值为介于1到1,000,000,000之间的整数。

3.最大值与最小值之差K为介于1到1,000,000,000之间的整数。

4.一个数列中的数值不存在重复的情况。

 

[输入]

首先给出测试用例数量T,接着给出T种测试用例。每个测试用例的第一行空格区分给出数字个数N,以及最大值与最小值之差K。第二行空格区分给出N个数值。

 

[输出]

每个测试用例输出一行。各测试用例都输出“#x”(其中x表示测试用例编号,从1开始),隔一个空格后,请输出满足最大值与最小值之差为K的子数列中,长度最短的子数列长度和长度最短的子数列的个数。如果没有满足最大值与最小值之差为K的子数列,则输出 -1。

 

[输入输出 示例]
(输入)

4
10 10
1 7 2 5 11 17 13 21 3 6
8 3
6 1 2 4 3 5 9 7
4 10
7 2 4 3
12 100
2 49 1 90 51 101 149 151 112 152 113 222

(输出)
#1 4 1
#2 3 1
#3 -1
#4 4 2

 

思路分析:
要求区间最大值、最小值,首先考虑Indexed Tree
如果逐个去查寻最大值最小值并求差值,数据量为10W,效率肯定过不去,因此需要反向思维,即数据从小到大排序后,逐个找当前数+K的数(有序,可使用二分查找)
如果当前数+K存在,则去原数组中,找两个数之间的最大值与最小值,如果最大值=当前数+K且最小值=当前数,则此区间是区满足题目条件的区间

 

package tree;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
/**
 * 思路:要求区间最大值、最小值,首先考虑Indexed Tree
 * 如果逐个去查寻最大值最小值并求差值,数据量为10W,效率肯定过不去,因此需要反向思维,即数据从小到大排序后,逐个找当前数+K的数(有序,可使用二分查找)
 * 如果当前数+K存在,则去原数组中,找两个数之间的最大值与最小值,如果最大值=当前数+K且最小值=当前数,则此区间是区满足题目条件的区间
 * @author XA-GDD
 *
 */
public class EQ_Sequence_0329 {
	static int T,N, K;
	static int _max_Nval = 100000;
	static Node []srcArr = new Node[_max_Nval];
	static long[] maxIdxTree = new long[_max_Nval*4]; //最大值Indexed Tree
	static long [] minIdxTree = new long[_max_Nval*4]; //最小值Indexed Tree
	static int offset;
	static int seqLength;
	static int seqCnt;
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("D:\\workspace\\sw_pro\\sample_input_0329.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	    StringTokenizer st = new StringTokenizer(br.readLine());
		T = Integer.parseInt(st.nextToken());
	    for(int testCase = 1; testCase<=T;testCase++) {
	    	
	    	
	    	st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			K = Integer.parseInt(st.nextToken());
						
			//初始化Tree
			int k=0;
			while((1<<k)<N) {
				k++;
			}
			offset = 1<<k;
			
			Arrays.fill(maxIdxTree, Long.MIN_VALUE);
			Arrays.fill(minIdxTree, Long.MAX_VALUE>>1);
			Arrays.fill(srcArr, null);
			seqLength = Integer.MAX_VALUE;
			seqCnt = 0;
			
			st = new StringTokenizer(br.readLine());
			for(int i=0;i<N;i++) {
				srcArr[i] = new Node(i,Integer.parseInt(st.nextToken()));
				//将原数组更新到Tree上
				update(offset+i,srcArr[i].val);
			}
			
			//将原数组按照从小到大排序
			Arrays.sort(srcArr, 0, N);
			
			
			for(int i=0;i<N;i++) {
				//按照排序后的顺序,使用二分查找,逐个找当前数+K的数
				int idx = Arrays.binarySearch(srcArr, 0, N, new Node(0,srcArr[i].val+K));
				
				if(idx>0) {
					int left = (int) Math.min(srcArr[i].idx, srcArr[idx].idx); //两个数在原数组靠前的,在tree中的位置靠左
					int right = (int) Math.max(srcArr[i].idx, srcArr[idx].idx); //两个数在原数组靠后的,在tree中的位置靠右
					
					//如果最大值=当前数+K且最小值=当前数,则此区间是区满足题目条件的区间
					if(query(left+offset,right+offset,srcArr[i].val,srcArr[i].val+K)) {
						int length = right-left+1;
						if(length==seqLength) {
							seqCnt++;
						}else if(length<seqLength) {
							seqLength = length;
							seqCnt=1;
						}
					}
				}
			}
			if(seqCnt==0) {
				System.out.printf("#%d %d\n",testCase,-1);
			}else {
				System.out.printf("#%d %d %d\n",testCase,seqLength,seqCnt);
			}
			
	    }
	}
	
	static void update(int index , long value) {
		maxIdxTree[index] = value;
		minIdxTree[index] = value;
		index = index >> 1;
		while(index>0) {
			maxIdxTree[index] = Math.max(maxIdxTree[index*2], maxIdxTree[index*2+1]);
			minIdxTree[index] = Math.min(minIdxTree[index*2], minIdxTree[index*2+1]);
			index = index >> 1;
		}
	}

	static boolean query(int start, int end, long leftVal, long rightVal) {
		long minVal = Long.MAX_VALUE>>1;
		long maxVal = Long.MIN_VALUE;
		while(start<=end) {
			if(start%2==1){
				minVal = Math.min(minVal, minIdxTree[start]);
				maxVal = Math.max(maxVal, maxIdxTree[start]);
			}
			if(end%2==0){
				minVal = Math.min(minVal, minIdxTree[end]);
				maxVal = Math.max(maxVal, maxIdxTree[end]);
			}
			start = (start+1)>>1;
			end = (end-1)>>1;
		}
		return minVal == leftVal && maxVal == rightVal;
	}
	
	static class Node implements Comparable<Node>{
		int idx;
		int val;
		Node(int idx , int val){
			this.idx = idx;
			this.val = val;
		}
		@Override
		public int compareTo(Node o) {
			return this.val - o.val;
		}
	}
}

  

上一篇:linux 下nginx


下一篇:利用Spring之NamedParameterJdbcTemplate批量插入和更新Oracle+Sequence