239. 滑动窗口最大值

embedded/2024/10/11 1:09:08/
最初想法:用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/embedded/125644.html

相关文章

CF2018C Tree Pruning 题解

Description 给定一棵有 n n n 个点的以 1 1 1 为根的树&#xff0c;在此问题中&#xff0c;叶子节点被定义为非根的度数为一的点。 每次操作可以删去一个叶子节点及其相连的边&#xff0c;你需要求出最小的操作次数&#xff0c;使得操作后所有叶子节点到根节点的距离相同。…

变换器(Transformer)在医学成像中的应用(上)

在自然语言任务上取得前所未有的成功之后&#xff0c;Transformer已被成功应用于多个计算机视觉问题&#xff0c;取得了最先进的结果&#xff0c;并促使研究人员重新考虑卷积神经网络(CNNs)作为事实上标准操作符的优势地位。利用计算机视觉领域的这些进展&#xff0c;医学影像领…

byte[]/InputStream/MultipartFile之间进行转换

前言 问题产生&#xff1a; 最近开发项目的时候&#xff0c;遇到了文件上传对象转换的问题 -> 我在对接抖音开放平台的时候&#xff0c;有一个图片上传的接口&#xff0c;需要将byte[]转为MultipartFile 对象&#xff0c;但是发现根本没有这样的工具类&#xff0c;后面翻阅…

[k8s理论知识]1.runc容器管理工具

runc是一个用来启动和管理容器的轻量级工具&#xff0c;它是开放容器项目(Open Container Initiative, OCI)的标准实现。runc 是一个 CLI 工具&#xff0c;用于根据 OCI 规范创建和运行容器。它是容器底层的核心组件&#xff0c;负责直接与 Linux 内核的 cgroups 和 namespaces…

MinIO分片上传超大文件(纯服务端)

目录 一、MinIO快速搭建1.1、拉取docker镜像1.2、启动docker容器 二、分片上传大文件到MinIO2.1、添加依赖2.2、实现MinioClient2.3、实现分片上传2.3.0、初始化MinioClient2.3.1、准备分片上传2.3.2、分片并上传2.3.2.1、设置分片大小2.3.2.2、分片 2.3.3、分片合并 三、测试3…

python xml的读取和写入

import xml.etree.ElementTree as ET from xml.dom import minidom# 读取XML文档 tree ET.parse("./xml_3/z_20240827_001.xml") root tree.getroot() # 获取size元素 size_find_0 root.find("size") # 获取width子元素 size_w size_find_0.find("…

Cocos_鼠标滚轮放缩地图

文章目录 前言一、环境二、版本一_code2.分析类属性方法详细分析详细分析onLoad()onMouseWheel(event)详细分析 总结 前言 学习笔记&#xff0c;请多多斧正。 一、环境 通过精灵rect放置脚本实现鼠标滚轮放缩地图。 二、版本一_code import { _decorator, Component, Node }…

《Java程序员面试宝典》——(第二章节)

当前因为经济大环境不好、大厂裁员、就业情况差、企业要求变高、各行各业越来越卷&#xff0c;尤其是程序员&#xff0c;处于这个阶段&#xff0c;感觉特别明显&#xff01; 对于程序员这个群体来说&#xff0c;java程序员的占比就非常之高&#xff0c;就业市场等于说是千军万…