股价浮动范围 - Box Pattern - Indexed Tree
股价浮动范围
时间限制:最多30个用例,1秒(C/C++),1.5秒 (Java)/内存限制:256 MB(Stack 1 MB)
假设会提供某家公司N天期间的股票价格。你偶尔会用过去的股票价格进行模拟投资,但是股票价格的剧烈波动会使你感到不安,所以你想了解股票价格在什么时间段内几乎保持不变。这里的价格几乎不变,表示的是在一段时间内的股票最大值和最小值之差为小于给出的K值。
例如,如上一样给出过去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); } }