双指针在一定条件下可以转化成滑动窗口,这道题就是个很好的例子
LeetCode链接:643. 子数组最大平均数 I
1.题目描述
给你一个由 n
个元素组成的整数数组 nums
和一个整数 k
。
请你找出平均数最大且 长度为 k
的连续子数组,并输出该最大平均数。
任何误差小于 10-5
的答案都将被视为正确答案。
示例 1:
1 2 3
| 输入:nums = [1,12,-5,-6,50,3], k = 4 输出:12.75 解释:最大平均数 (12-5-6+50)/4 = 51/4 = 12.75
|
示例 2:
1 2
| 输入:nums = [5], k = 1 输出:5.00000
|
提示:
n == nums.length
- $1 <= k <= n <= 10^5$
- $-10^4 <= nums[i] <= 10^4$
2.题解
2.1 暴力解法(超出时间限制)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class Solution { public double findMaxAverage(int[] nums, int k) { double maxAverage = Double.NEGATIVE_INFINITY;
for (int i = 0; i <= nums.length - k; i++) { int sum = 0; for (int j = i; j < i + k; j++) { sum += nums[j]; } double average = (double) sum / k; maxAverage = average > maxAverage ? average : maxAverage; }
return maxAverage; } }
|
2.2 双指针
- 由于每次都要计算平均值,所以在这里做一个处理,先求出长度为
k
的区间和的最大值,返回时再求平均
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Solution { public double findMaxAverage(int[] nums, int k) { int maxSum = Integer.MIN_VALUE; int left, right; int sum = 0; for (left = 0, right = 0; right < nums.length; right++) { sum += nums[right]; if (right - left + 1 == k) { maxSum = Math.max(maxSum, sum); } while (right - left + 1 >= k) { sum -= nums[left]; left++; } } return (double) maxSum / k; } }
|
2.3 双指针优化=>滑动窗口
- 由于所求的窗口的长度是固定的,因此首先计算出数组前
k
个区间的和,然后再向后滑动区间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class Solution { public double findMaxAverage(int[] nums, int k) { int maxSum = 0; for (int i = 0; i < k; i++) { maxSum += nums[i]; }
int currentSum = maxSum;
for (int i = k; i < nums.length; i++) { currentSum = currentSum - nums[i - k] + nums[i];
if (currentSum > maxSum) { maxSum = currentSum; } }
return (double) maxSum / k; } }
|