一、问题描述
小U有一个长度为n的整数数组,并且选择了一个有理数 u/v。他现在想知道这个数组中有多少个连续的子区间,其平均值恰好等于 u/v。数组的子区间是指数组中一段连续的元素。
例如,给定数组 [2, 4, 1, 3, 2, 3] 和有理数 5/2,我们需要找出所有平均值等于 5/2 的子区间。
二、测试样例
样例1:
输入:
n = 6 ,u = 5 ,v = 2 ,arr = [2, 4, 1, 3, 2, 3]输出:
6
样例2:
输入:
n = 5 ,u = 1 ,v = 1 ,arr = [1, 1, 1, 1, 1]输出:
15
样例3:
输入:
n = 4 ,u = 2 ,v = 1 ,arr = [2, 2, 2, 2]输出:
10
三、思路
连续子区间可以用两个指针表示,i为子区间开头,j为子区间具体的数字索引,用浮点数计算并保存u/v的值。用sum保存子区间数字的和,l表示子区间的长度,sum/l可以得到子区间的平均值,用该平均值与u/v的值比对。相等的话,符合条件的子区间数量加一。
四、代码
public static int solution(int n, int u, int v, int[] arr) {
int l;
double num=(double)u/(double)v;
int result=0,sum=0;
for(int i=0;i<n;i++){
sum=0;
l=0;
for(int j=i;j<n;j++){
sum+=arr[j];
l++;
if((double)sum/(double)l==num){
result++;
}
}
}
return result;
}
五、代码详解
double num=(double)u/(double)v;
用num保存u/v的值
for(int i=0;i<n;i++){
sum=0;
l=0;
for(int j=i;j<n;j++){
sum+=arr[j];
l++;
if((double)sum/(double)l==num){
result++;
}
}
}
该内部循环中,i是子区间的开头,j是子区间的具体索引,sum是子区间的和,l是子区间长度。子区间开头不变,长度变化。长度每变一次,都要重新计算该子区间的平均值,并与u/v的值比对。外部循环中,子区间开头变化,子区间的和和子区间长度重新为0.
六、图解
样例:
输入:
n = 3 ,u = 2 ,v = 1 ,arr = [1, 2, 3]输出:
10
u/v=2/1=2
| i=0 | j=0 | j=1 | j=2 |
|---|---|---|---|
| 区间 | [1] | [1,2] | [1,2,3] |
| 和 | 1 | 3 | 6 |
| 长度 | 1 | 2 | 3 |
| 平均值 | 1 | 1.5 | 2 |
| i=1 | j=1 | j=2 |
|---|---|---|
| 区间 | [2] | [2,3] |
| 和 | 2 | 5 |
| 长度 | 1 | 2 |
| 平均值 | 2 | 2.5 |
| i=2 | j=2 |
|---|---|
| 区间 | [3] |
| 和 | 3 |
| 长度 | 1 |
| 平均值 | 3 |
选择以下情况,能满足题目要求。
- i=0,j=2
- i=1,j=1
所以有两种情况符合连续的子区间,其平均值恰好等于 u/v,结果为2。