股价浮动范围 - Box Pattern - Indexed Tree

股价浮动范围

时间限制:最多30个用例,1秒(C/C++),1.5秒 (Java)/内存限制:256 MB(Stack 1 MB)

假设会提供某家公司N天期间的股票价格。你偶尔会用过去的股票价格进行模拟投资,但是股票价格的剧烈波动会使你感到不安,所以你想了解股票价格在什么时间段内几乎保持不变。这里的价格几乎不变,表示的是在一段时间内的股票最大值和最小值之差为小于给出的K值

股价浮动范围 - Box Pattern - Indexed Tree

 

 

例如,如上一样给出过去10天的股票价格以及K=10的情况,可以说明除了股票价格为15的最后一天之外,其他9天内的价格几乎没有变化。(前9天的最大值为13,最小值为3,二者之差为10,这满足K=10。但在第10天,股票价格为15,其与跟最小值3的差为12,这超过了 K=10。)另外,9天是股票价格几乎没有变化的最长持续时间。

编写一个程序,计算出在给定期间内股票最大值与最小值之差小于等于K的最长持续时间

 

[限制条件]

1.天数N为介于1到300,000之间的整数。

2.股票价格为介于1到1,000,000,000之间的整数。

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

 

[输入]

第一行给出测试用例数量T。接着给出T个测试用例。各测试用例的第一行空格区分给出总天数N和K。下一行空格区分按时间由远至近的顺序依次给出N天的股票价格。

 

[输出]

各测试用例的答案按照顺序标准输出。对于每个用例输出“#x”(x 为测试用例编号,从1 开始),加一个空格(不包含引号),输出题目中要求的满足条件的最长持续时间长度(天数)。

 

[输入输出 示例]

(输入)

3

10 10

17 25 22 15 18 18 21 12 5 25

10 10

8 11 3 10 11 7 7 13 10 15

1 1

1000000000

 

(输出)

#1 7

#2 9

#3 1

 

解决思路:

 1.求区间最大值与最小值,即区间极值,使用Indexed Tree, 需要声明两个tree
 2.区间是变动的,可考虑双指针,此题目,区间左右都在移动,但移动速度不一样,可使用快慢指针
 3.天数N<300000, 则无需散列化

 

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;

/**
 * 解决思路:
 * 1.求区间最大值与最小值,即区间极值,使用Indexed Tree,声明两个tree
 * 2.区间是变动的,可考虑双指针,此题目,区间左右都在移动,但移动速度不一样,可使用快慢指针
 * 天数N<300000, 则无需散列化
 * 
 * @author XA-GDD
 *
 */
public class EQ_BoxPattern_0705 {

	static int T,N,K;
	static int _Max_N = 300000;
	static int [] srcArr = new int[_Max_N+2];
	static int [] minIdxTree = new int[(_Max_N)*4]; //区间最小值tree
	static int [] maxIdxTree = new int[(_Max_N)*4]; //区间最大值tree
	static int offset;
	static int ans;
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("D:\\workspace\\eclipse-workspace\\sw_pro\\test_case\\sample_input_0705.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++) {
	    	init();
	    	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;	    	
	    	st = new StringTokenizer(br.readLine());
	    	for(int i=0;i<N;i++) { //每读取一个值,更新区间的最大值和最小值
	    		update(offset+i,Integer.parseInt(st.nextToken()));
	    	}
	    	getLongestTime();
	    	System.out.println("#"+testCase+" "+ans);
	    	
	    }
	}
	
	static void getLongestTime() {
		
		int fast = 0; //快指针
		int slow = 0; //慢指针
		for(int i=0;i<N;i++) { 	
			fast = i;			
			int difVal = query(offset+slow,offset+fast);
			while(difVal>K) { //差值超出K的范围了,那么慢指针移动
				slow++;
				difVal = query(offset+slow,offset+fast);
			}
			ans = Math.max(ans, fast-slow+1);	
		}
	}
	
	//更新最大值及最小值
	static void update(int index ,int val) {
		minIdxTree[index] = val;
		maxIdxTree[index] = val;
		index= index>>1;
	    while(index>0) {
	    	minIdxTree[index] = Math.min(minIdxTree[index*2], minIdxTree[index*2+1]);
	    	maxIdxTree[index] = Math.max(maxIdxTree[index*2], maxIdxTree[index*2+1]);
	    	index = index>>1;
	    }
	}
	
	//查询最大值与最小值之差
	static int query(int start ,int end) {
		int minRes = Integer.MAX_VALUE;
		int maxRes = Integer.MIN_VALUE;
		while(start<=end) {
			if(start%2==1) {
				minRes = Math.min(minRes, minIdxTree[start]);
				maxRes = Math.max(maxRes, maxIdxTree[start]);
			}
			if(end%2==0) {
				minRes = Math.min(minRes, minIdxTree[end]);
				maxRes = Math.max(maxRes, maxIdxTree[end]);
			}
			start = (start+1)>>1;
			end = (end-1)>>1;
		}
		return maxRes-minRes;
	}
	
	static void init() {
		ans=0;
		Arrays.fill(srcArr,0);
    	Arrays.fill(minIdxTree, Integer.MAX_VALUE);
    	Arrays.fill(maxIdxTree, Integer.MIN_VALUE);
	}

}

  

上一篇:有趣的跳跃


下一篇:Hoo虎符研究院|Coinwave Production - 什么是Chromia公链