源地址
https://app.codility.com/programmers/lessons/4-counting_elements/max_counters/
MaxCounters(计数器)
给定N个计数器,初始值为0,对于他们你有两个可能的操作
- increase(X) 计数器X递增1
- max counter 所有的计数器被设定为最大计数器的值
给定一个含有M个整数的非空数组A。这个数组代表如下操作:
- 如果 A[K] = X,而1 ≤ X ≤ N,那么操作就是increase(X)
- 如果 A[K] = N+1,那么操作就是max counter
比如,给定整数N= 5 ,和数组A如下:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
在每一个连续操作之后计数器的值如下:
(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)
目标是计算在所有操作之后的各个计数器的值。
写一个函数
class Solution {
public int[] solution(int N, int[] A);
}
给定一个整数N,和包含M个整数的非空数列A,返回代表各个计数器的值的一串整数。
结果集应该作为一个整数数列返回。
比如,给定
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
函数应该返回[3, 2, 2, 4, 2]
假定:
- N和M是范围在[1…100,000]的整数
- 数列A中的每个元素都是在范围[1…N + 1]的整数
第一步
完全按照题中解释的逻辑实现,时间复杂度感人。
public int[] solution(int N, int[] A) {
int[] B = new int[N];
int max = 0;
for (int a : A) {
if (a <= N) {
B[a - 1]++;
max = Math.max(max, B[a - 1]);
} else {
Arrays.fill(B, max);
}
}
return B;
}
第二步
更快的方法是每次max counter的时候,记录下这个水平面的值,而不是把所有计数器的值重新设置。
public int[] solution(int N, int[] A) {
int[] B = new int[N];
int max = 0;
int level = 0;
for (int a : A) {
if (a <= N) {
if (B[a - 1] < level) {
B[a - 1] = level + 1;
} else {
B[a - 1]++;
}
max = Math.max(max, B[a - 1]);
} else {
level = max;
}
}
for (int i = 0; i < N; i++) {
if (B[i] < level) {
B[i] = level;
}
}
return B;
}