股价浮动范围 - 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);
}
}
浙公网安备 33010602011771号