本题大意:
给一个数组和一个数字 如{1,2,3,4,4,7}和4。
首先算出前四个数字({1,2,3,4})的中位数的两倍,如果第五个数字(4)大于他,则计数+1。然后再比较下四个数字({2,3,4,4})和下一个数(7)。以此类推,最后给出计数的数量即可。
* 中位数逻辑,如果数组元素数量为奇数,则为排序后最中间的数,如果是偶数,则是最中间两个数的均值。
如{3,1,2,1}的中位数是1.5,{2,3,4,3,2}的中位数是3
……………………………………………………
这题正常计算比较简单,但是正常的计算方法都会超时。
最正常的算法:
先求出中位数,然后一直比较即可。但是我们看数据大小:

最差的情况,n = 10^5 d=10^5,计算中位数算法的复杂度为O(n)~O(nlogn)之间,就算用最好的O(n)方法,时间也达到了n*d = 10^10,会直接超时(一般的算法超过10^8 即一亿 就会超时)
但是看了一下数据的特点,所有的数值都在0~200之间,在n很大的时候,大部分的数值都是重复的。
所以用map储存各个元素数量的方法就出现了,即记录每个元素出现过多少次,这样计算中位数就很方便了。
如我们需要找{2,2,2,1,3,2,2}的中位数,我们只需要记下来这里面有1个1,5个2,1个3,这样就可以不用排序很容易的算出中位数了。
另外用这种方式储存时,当计算下一个中位数的时候,由于大部分元素没有变,只是移除了开头一个元素,加入了后面一个元素。所以计数也非常简单。(如{1,2,3,4,4,7}和4,第一个需要算中位数的数组是{1,2,3,4},第二个是{2,3,4,4},只需要移除一个1加进来一个4即可,很方便计数)
这么一拨操作之后,时间复杂度就够用了。
……………………………………………………………………………………………………
static int activityNotifications(int[] expenditure, int d) {
int len = expenditure.length;
if (len == d) {
return 0;
}
int count = 0;
for (int i = d; i < len ; i ++) {
if (i == d) {
initMap(Arrays.copyOfRange(expenditure, 0, i));
} else {
move(expenditure[i - d - 1], expenditure[i - 1]);
}
int mid = get2Mid(d);
if (expenditure[i] >= mid) {
count ++;
}
}
return count;
}
private static void initMap(int[] copyOfRange) {
for (int i : copyOfRange) {
if (temps.containsKey(i)) {
temps.put(i, temps.get(i) + 1);
} else {
temps.put(i, 1);
}
}
}
static HashMap<Integer, Integer> temps = new HashMap<>();
private static void move(int moveout, int movein) {
if (temps.containsKey(movein)) {
temps.put(movein, temps.get(movein) + 1);
} else {
temps.put(movein, 1);
}
temps.put(moveout, temps.get(moveout) - 1);
}
static int get2Mid(int total) {
if (total % 2 == 1) {
int target = total / 2 + 1;
int count = 0;
for (int i = 0; i < 201; i++) {
if (temps.containsKey(i)) {
count += temps.get(i);
if (count >=target) {
return i * 2;
}
}
}
} else {
int target1 = total / 2;
int target2 = total / 2 + 1;
int final1 = -1;
int final2 = -1;
int count = 0;
for (int i = 0; i < 201; i++) {
if (temps.containsKey(i)) {
count += temps.get(i);
if (count >= target1 && final1 < 0) {
final1 = i;
}
if (count >= target2) {
final2 = i;
return final1 + final2;
}
}
}
}
return -1;
}