Given an array consisting of n
integers, find the contiguous subarray of given length k
that has the maximum average value. And you need to output the maximum average value.
给定一个由n个整数组成的数组,查找给定长度k的连续子数组,它具有最大的平均值。你需要输出最大的平均值。
Example 1:
Input: [1,12,-5,-6,50,3], k = 4 Output: 12.75 Explanation: Maximum average is (12-5-6+50)/4 = 51/4 = 12.75
Note:
- 1 <=
k
<=n
<= 30,000. - Elements of the given array will be in the range [-10,000, 10,000]
在解决这道题时,首先要搞清楚题意,其一,并不是求最大子段和。其二,k是已经给定的。
当明白了这两个点后,便可以进入解题阶段。
我解决这道题的做法便是,暴力查找。设定一个游标j,它从数组的初始位置(0号位置)开始,向后查k个单位,并计算j到j+k-1的值。然后依次相后移动j,重复上面操作。将每一次取得的和,作比较,保留最大的即可。附上代码:
public class Solution
{
public double findMaxAverage(int[] nums, int k)
{
double a=helper(nums,k);
return a;
}
public double helper(int []nums, int k)
{
//暂存字段和的值
int max=0,t=0,j=0,sum=0;
double average=0;
//循环变量
int i=0;
if(nums.length==1)
max=nums[0];
while((j+k-1)<=nums.length-1)
{
for(i=j;i<=j+k-1;i++)
{
t+=nums[i];
}
if(j==0)
max=t;
j++;
max=Math.max(max,t);
t=0;
}
average=(double)max/k;
return average;
}
}
需要注意的点:
①for循环中,i<=j+k-1这个条件,切不可因为i=j,便将条件改写为i<=i+k-1,因为i++后,下一次循环时i的值便发生了变化。
②要考虑到只有一个数值的数组,直接返回即可。
③需要注意到,每一次求值后比较时,都应该是和上一次的值进行比较,保留下较大值。故此,第一次求和时,一定要保留。以后的每次求和比较才可以顺利进行。
④要做到强类型转换。
⑤while循环条件一定要处理好,是nums.length-1,而不是nums.length,否则数组会超界。
大神做法:
public class Solution {
public double findMaxAverage(int[] nums, int k) {
long sum = 0;
for (int i = 0; i < k; i++) sum += nums[i];
long max = sum;
for (int i = k; i < nums.length; i++) {
sum += nums[i] - nums[i - k];
max = Math.max(max, sum);
}
return max / 1.0 / k;
}
}
这个做法十分巧妙,他忽略了每一个数组值得累加,而是通过减法间接实现增加。
sum += nums[i] - nums[i - k];
这一条语句是最关键的。加入k为2,那么第一次循环便是求nums[0],nums[1],这两个数组元素的和sum。那么递推相后,下一次便是求nums[1],nums[2]的和。经比较可以发现,nums[1]是多余的,因为每一次的求和,它都存在。那么。第二次求和时,可以在第一次的基础上,加上nums[2]与nums‘’[0]的差值。即为:nums[2]-nums[0]+sum==nums[2]-nums[0]+nums[1]+nums[0]=nums[1]+nums[2]。故以此类推,即可得到这一规律
sum += nums[i] - nums[i - k];