范围:[1, 105]
public static long numOfK(int[] nums, int k) {
int len = nums.length;
//long[] pre = new long[len + 1];
long sum = 0;
long[] y = new long[k];
for (int i = 1; i <= len; i++) {
//pre[i] += nums[i - 1] + pre[i - 1];
sum += nums[i];
y[(int) (sum % k)]++;
}
long res = y[0];
for (int i = 0; i < k; i++) {
res += y[i] * (y[i] - 1) / 2;
}
return res;
}
关键
-
虽然要计算前缀和,但是此题不需要使用每个元素的前缀和,所以无需使用数组
pre[]
去记录每个元素的前缀和,只需要sum
记录一下(一次性)。 -
为什么数组
y[]
(记录相同余数个数)是long
类型?- 为什么会涉及到
long
?
因为本题的范围是105,在记录前缀和时max(N*K) = 1010,超过int
。 - 数组
y[]
是用来存余数,余数<k∈[1, 105](余数<除数),为什么还需要用long
?
因为这行代码:
res += y[i] * (y[i] - 1) / 2;
根据运算顺序,先计算乘除,这就意味着:如果
y[]
是int
,那么在进行y[i] * (y[i] - 1) / 2
运算时,如果超过了int
范围,依然会转成int
(有损失)。其实,
y[]
可以用int y[]
,但是在这行代码得调整为:res += (long)y[i] * (y[i] - 1) / 2; //int往高类型long转换
Q:那
sum += nums[i];
没有这样的问题吗?(long sum
/int[] nums
)
A:sum += nums[i]
本质上是sum = sum + nums[i] // 往高类型转换
但是,
res += y[i] * (y[i] - 1) / 2
=>res = res + y[i] * (y[i] - 1) / 2
是先计算乘除,乘除后结果仍是int
(在此处损失),再和long
相加。 - 为什么会涉及到