数列
测试用例总数:40 个用例,1.5 秒 (C/C++),2 秒 (JAVA)
当前有一组包含N个数字的数列。当从数列中选取几个连续的数字时,想在这些选择的数字中创建最小值和最大值差为K的子数列。请求出最大值和最小值差为K的子数列中长度为最短的情况。
下面案例是从包含10个数的数列中找出K为10的子数列。
为方便起见,数列的第一个数字开始定义为 index 1, index 2, …, index 10
当选择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; } } }