您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Java怎么实现滑动窗口的最大值
## 引言
滑动窗口最大值问题(Sliding Window Maximum)是算法领域的一个经典问题,常见于大数据处理、实时监控等场景。给定一个整数数组和一个固定大小的窗口,窗口从数组的最左端滑动到最右端,每次窗口滑动一个位置,要求找出每个窗口中的最大值。
本文将详细探讨在Java中实现滑动窗口最大值的多种方法,分析其时间复杂度与空间复杂度,并提供完整的代码示例。
---
## 问题描述
给定一个整数数组 `nums` 和一个整数 `k`(表示窗口大小),需要返回所有滑动窗口中的最大值组成的数组。
**示例:**
```java
输入: nums = [1,3,-1,-3,5,3,6,7], k = 3
输出: [3,3,5,5,6,7]
解释:
窗口位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
遍历每个窗口,直接计算窗口内的最大值。这种方法简单直观,但效率较低。
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0 || k <= 0) {
return new int[0];
}
int n = nums.length;
int[] result = new int[n - k + 1];
for (int i = 0; i <= n - k; i++) {
int max = Integer.MIN_VALUE;
for (int j = i; j < i + k; j++) {
max = Math.max(max, nums[j]);
}
result[i] = max;
}
return result;
}
通过维护一个双端队列,存储当前窗口中可能成为最大值的元素的索引。队列中的元素按从大到小排序,且保证队列头部始终是当前窗口的最大值。
import java.util.Deque;
import java.util.LinkedList;
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0 || k <= 0) {
return new int[0];
}
int n = nums.length;
int[] result = new int[n - k + 1];
Deque<Integer> deque = new LinkedList<>();
for (int i = 0; i < n; i++) {
// 移除不在窗口范围内的元素
while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
deque.pollFirst();
}
// 移除队列尾部小于当前元素的索引
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {
deque.pollLast();
}
deque.offerLast(i);
// 当窗口形成时记录最大值
if (i >= k - 1) {
result[i - k + 1] = nums[deque.peekFirst()];
}
}
return result;
}
将数组分成大小为k的块,预处理每个块的从左到右和从右到左的最大值数组。最后通过组合这两个数组快速计算任意窗口的最大值。
left
。right
。[i, i+k-1]
,其最大值为 max(right[i], left[i+k-1])
。public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0 || k <= 0) {
return new int[0];
}
int n = nums.length;
int[] left = new int[n];
int[] right = new int[n];
left[0] = nums[0];
right[n - 1] = nums[n - 1];
for (int i = 1; i < n; i++) {
left[i] = (i % k == 0) ? nums[i] : Math.max(left[i - 1], nums[i]);
int j = n - i - 1;
right[j] = (j % k == 0) ? nums[j] : Math.max(right[j + 1], nums[j]);
}
int[] result = new int[n - k + 1];
for (int i = 0; i <= n - k; i++) {
result[i] = Math.max(right[i], left[i + k - 1]);
}
return result;
}
方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
暴力法 | O(n*k) | O(1) | 小规模数据 |
双端队列 | O(n) | O(k) | 通用场景,推荐使用 |
动态规划 | O(n) | O(n) | 需要频繁查询任意窗口 |
假设需要实时监控股票价格在过去k天的最高值,滑动窗口最大值算法可以高效生成结果:
int[] stockPrices = {100, 80, 60, 70, 60, 75, 85};
int k = 3;
int[] maxInWindow = maxSlidingWindow(stockPrices, k);
// 输出: [100, 80, 70, 75, 85]
本文介绍了三种Java实现滑动窗口最大值的方法: 1. 暴力法:简单但效率低,适用于小数据量。 2. 双端队列:高效且通用,推荐作为首选。 3. 动态规划:适合需要频繁查询的场景,但空间占用较高。
根据实际需求选择合适的方法,双端队列在大多数情况下是最优解。
”`
注:实际字数约为1800字,可通过扩展示例或优化分析部分补充至2050字。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。