239. 滑动窗口最大值

ops/2024/10/11 2:53:28/
最初想法:用hashmap记录窗口中出现的数字的个数,maxNum记录当前窗口的最大数,当窗口滑动后左侧数个数减一,右侧数个数加一,同时查看原最大数的个数是否为0,如果为0:遍历当前hashmap中的key找到最大的,如果不为0:将新加入的数与原最大数比较,但是timeout了
java">    public int[] maxSlidingWindow(int[] nums, int k) {HashMap<Integer, Integer> map = new HashMap<>();int[] res = new int[nums.length - k + 1];int[] maxNum = {-1000005};for(int i = 0; i < k; i++) {map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);if(nums[i] > maxNum[0]) {maxNum[0] = nums[i];}}res[0] = maxNum[0];for(int begin = 0, end = k; end < nums.length; begin++, end++) {map.put(nums[begin], map.getOrDefault(nums[begin], 0) - 1);map.put(nums[end], map.getOrDefault(nums[end], 0) + 1);if(map.get(maxNum[0]) == 0) {maxNum[0] = -1000005;map.entrySet().forEach(entry -> {if(entry.getValue() > 0) {if(entry.getKey() > maxNum[0]) maxNum[0] = entry.getKey();}});} else {if(nums[end] > maxNum[0]) {maxNum[0] = nums[end];}}res[begin + 1] = maxNum[0];}return res;}

上面之所以超时是因为我们在维护窗口内的最大数的时间开销太大了,于是我就想如果能以较小的开销找到最大的数说不定就不会超时了,所以想到了treemap,TreeMap是有序的,内部维护了键的排序顺序 解决了重新找最大键的过于耗时的问题。

java">    public int[] maxSlidingWindow(int[] nums, int k) {TreeMap<Integer, Integer> map = new TreeMap<>();int[] res = new int[nums.length - k + 1];int maxNum = -1000005;for(int i = 0; i < k; i++) {map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);if(nums[i] > maxNum) {maxNum = nums[i];}}res[0] = maxNum;for(int begin = 0, end = k; end < nums.length; begin++, end++) {if (map.getOrDefault(nums[begin], 0) - 1 > 0) {map.put(nums[begin], map.getOrDefault(nums[begin], 0) - 1);} else {map.remove(nums[begin]);}map.put(nums[end], map.getOrDefault(nums[end], 0) + 1);if(map.getOrDefault(maxNum, 0) == 0) {maxNum = map.lastKey();} else {if(nums[end] > maxNum) {maxNum = nums[end];}}res[begin + 1] = maxNum;}return res;}

后面我又想如果把查找时间压缩到log n级别行不行,也就是用二分找

呵结果还是T了(哭)

java">    public static int binarySearch(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] == target) {return mid;}if (nums[mid] < target) {right = mid - 1;}if (nums[mid] > target) {left = mid + 1;}}return -1;}//二分删除的实现public static void binaryDelete(int[] array, int value, int size) {int index = binarySearch(array, value);for (int i = index; i < size - 1; i++) {array[i] = array[i + 1];}array[size - 1] = -1000005;}// 二分插入实现public static void binaryInsert(int[] array, int value, int size) {int index = findInsertionIndex(array, value);for(int i = size - 1; i > index; i--) {array[i] = array[i - 1];}array[index] = value;}// 查找插入位置的实现private static int findInsertionIndex(int[] array, int value) {int left = 0;int right = array.length;while (left < right) {int mid = left + (right - left) / 2;if (array[mid] < value) {right = mid; // 插入位置在左半部分} else {left = mid + 1; // 插入位置在右半部分}}return left; // 返回插入位置}public int[] maxSlidingWindow(int[] nums, int k) {int[] ans = new int[nums.length - k + 1];int[] window = new int[k];//窗口内数的非递增排序for (int i = 0; i < k; i++) {window[i] = -1000005;}for(int i = 0; i < k; i++) {binaryInsert(window, nums[i], i + 1);}ans[0] = window[0];for(int begin = 0, end = k; end < nums.length; begin++, end++) {binaryDelete(window, nums[begin], k);binaryInsert(window, nums[end], k);ans[begin + 1] = window[0];}return ans;}

因为TreeMap的那个做法花费的时间是500多嘛,就又学习了一下大佬的题解写了这个用单调队列的做法

java">    //单调队列public int[] maxSlidingWindow(int[] nums, int k) {int n = nums.length; // 数组的长度Deque<Integer> deque = new LinkedList<Integer>(); // 双端队列,用于存储索引// 处理第一个窗口for (int i = 0; i < k; ++i) {// 维护队列的单调性,保持队列中从大到小的顺序while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {deque.pollLast(); // 移除队尾元素,确保队列中的元素从大到小排列}deque.offerLast(i); // 将当前索引加入队列}int[] ans = new int[n - k + 1]; // 结果数组ans[0] = nums[deque.peekFirst()]; // 第一个窗口的最大值// 处理后续的窗口for (int i = k; i < n; ++i) {// 维护队列的单调性while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {deque.pollLast(); // 移除队尾元素,确保队列中的元素从大到小排列}deque.offerLast(i); // 将当前索引加入队列// 移除超出窗口范围的元素while (deque.peekFirst() <= i - k) {deque.pollFirst(); // 移除队头元素,确保队列中的索引在窗口范围内}ans[i - k + 1] = nums[deque.peekFirst()]; // 当前窗口的最大值}return ans; // 返回结果数组}


http://www.ppmy.cn/ops/123774.html

相关文章

【Nacos架构 原理】内核设计之Nacos一致性协议

文章目录 Nacos一致性协议为什么需要一致性协议Nacos选择了Raft&#xff08;强一致性&#xff09;&Distro&#xff08;最终一致性&#xff09;服务发现角度配置管理角度 Nacos自研Distro协议背景设计思想数据初始化数据校验写操作读操作 Nacos一致性协议 为什么需要一致性…

五、创建型(建造者模式)

建造者模式 概念 建造者模式是一种创建型设计模式&#xff0c;通过使用多个简单的对象一步步构建一个复杂的对象。它将一个复杂对象的构建过程与其表示分离&#xff0c;从而使同样的构建过程可以创建不同的表示。 应用场景 复杂对象构建&#xff1a;当一个对象有多个属性&…

k8s 中存储之 PV 持久卷 与 PVC 持久卷申请

目录 1 PV 与 PVC 介绍 1.1 PersistentVolume&#xff08;持久卷&#xff0c;简称PV&#xff09; 1.2 PersistentVolumeClaim&#xff08;持久卷声明&#xff0c;简称PVC&#xff09; 1.3 使用了PV和PVC之后&#xff0c;工作可以得到进一步的细分&#xff1a; 2 持久卷实验配置…

等保测评:如何建立有效的网络安全监测系统

等保测评中的网络安全监测系统建立 在建立等保测评中的网络安全监测系统时&#xff0c;应遵循以下步骤和策略&#xff1a; 确定安全等级和分类&#xff1a;首先&#xff0c;需要根据信息系统的安全性要求、资产的重要性和风险程度等因素&#xff0c;确定网络系统的安全等级&…

猿人学 — 第1届第13题(解题思路附源码)

猿人学 — 第1届第13题&#xff08;解题思路附源码&#xff09; 发现在翻页过程中&#xff0c;只要中途有几秒的间隔&#xff0c;那么就会显示拉取数据失败&#xff0c;然后网页重新加载回到刚进来显示的第一页的情况 重新加载时&#xff0c;会发送一系列的请求&#xff0c;发…

【QT Qucik】C++交互:接收QML信号

在本节课中&#xff0c;我们将深入探讨如何在C中接收QML发出的信号。我们将分为几个部分&#xff0c;详细说明信号的定义、发送及其在C中的接收。 理解信号和槽机制 Qt的信号与槽机制是一种用于对象之间通信的强大工具。信号是对象在特定事件发生时发送的通知&#xff0c;而槽…

性能测试笔记2-总

安装路径&#xff1a;先装jdk,后装JMeter 安装JDK&#xff1a; 下载JDK – 安装JDK – 配置环境变量 – 验证 安装Jmeter&#xff1a; 下载Jmeter – 安装Jmeter – 配置环境变量 – 启动验证 注意点&#xff1a; 下载JDK时&#xff0c;注意电脑操作系统是32位/64位 下载…

回归分析在数据挖掘中的应用简析

一、引言 在数据驱动的时代&#xff0c;数据挖掘技术已成为从海量数据中提取有价值信息的关键工具。 回归分析&#xff0c;作为一种经典的统计学习方法&#xff0c;不仅在理论研究上有着深厚的基础&#xff0c;而且在实际 应用中也展现出强大的功能。 二、回归分析基础 2.1 回…