每天写两道(二)LRU缓存、数组中最大的第k个元素

2024-05-29 11:12

本文主要是介绍每天写两道(二)LRU缓存、数组中最大的第k个元素,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

146.LRU 缓存

. - 力扣(LeetCode)

请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。 

思路:双向链表+一个哨兵节点,使用map记录(key,node)

(图和思路都是偷力扣大佬的) 

实现:

class Node {constructor(key, value) {this.key = keythis.value = valuethis.pre = nullthis.next = null}
}class LRUCache {constructor(capacity) {this.capacity = capacitythis.dummy = new Node()this.dummy.next = this.dummythis.dummy.pre = this.dummy// 哈希表 用来存key和节点nodethis.keyToNodeMap = new Map()}// 删除x节点delete(x) {x.pre.next = x.nextx.next.pre = x.pre}// 将节点添加在链表头 哨兵节点后addTop(x) {x.pre = this.dummyx.next = this.dummy.nextx.pre.next = xx.next.pre = x}getNode(key) {// 没有该节点if (!this.keyToNodeMap.has(key)) { return null;}// 有 拿出来放在头部const node = this.keyToNodeMap.get(key); this.delete(node); this.addTop(node); return node;}get(key) {const node = this.getNode(key)return node?node.value:-1}put(key, value) {let node = this.getNode(key)// 有这个值 拿出来更新if (node) {node.value = value} else {// 新建节点放入node = new Node(key, value)this.keyToNodeMap.set(key, node)this.addTop(node)// 判断有没有溢出if (this.keyToNodeMap.size > this.capacity) {const backNode = this.dummy.prethis.keyToNodeMap.delete(backNode.key)this.delete(backNode)}}}
}

215.数组中最大的第k个元素

. - 力扣(LeetCode)

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 

思路:

看的是这位佬的:. - 力扣(LeetCode)

利用大根堆根节点最大的特性,构建大根堆,将根节点与最末尾节点交换,移出这个最大节点,再进行排序。。。

利用的是堆的思想,但实际是用数组来实现的 

顺序存储二叉树的特点:

第 n 个元素的 左子节点 为 2*n+1
第 n 个元素的 右子节点 为 2*n+2
第 n 个元素的 父节点 为 (n-1)/2
最后一个非叶子节点为 Math.floor(arr.length/2)-1

实现:

var findKthLargest = function (nums, k) {let len = nums.length// 先构建大根堆buildMaxHeap(nums, len)// 循环 将大根堆根节点和最末尾的节点交换// 循环到第k+1个最大就停止 最后返回的nums的根节点就是目标数// 这里for循环要用nums.length,不能用len,因为len是会改变的for (let i = nums.length - 1; i >= nums.length - k + 1; i--) {swap(nums, 0, i) // 将最大节点和最末尾的节点交换// 调整大根堆maxHeapify(nums, 0, --len) // 移到最后的节点不参与调整}return nums[0] // 返回第k个最大的值// 创建大根堆 自下而上构建大根堆function buildMaxHeap(nums, len) {// 最小非叶子节点:Math.floor(arr.length/2)-1for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {maxHeapify(nums, i, len)}}function maxHeapify(nums, i, len) {let left = i * 2 + 1 // i的左子节点let right = i * 2 + 2 // i的右子节点let largest = i // 最大值的节点下标// 和左子节点比较if (left < len && nums[left] > nums[largest]) {largest = left}// 和右子节点比较if (right < len && nums[right] > nums[largest]) {largest = right}if (i !== largest) {swap(nums, i, largest) // 将子节点与父节点交换maxHeapify(nums, largest, len) // 再继续向下比较}}function swap(nums, a, b) {let temp = nums[a]nums[a] = nums[b]nums[b] = temp}};

 今天写的两道都有点难,对于我这个白痴来说,所以明天还要再写一遍!!!

这篇关于每天写两道(二)LRU缓存、数组中最大的第k个元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1013509

相关文章

LeetCode--220 存在重复元素 III

题目 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。 示例 示例 1:输入: nums = [1,2,3,1], k = 3, t = 0输出: true示例 2:输入: nums = [1,0,1,1], k = 1, t = 2输出: true示例

LeetCode--217 存在重复元素

题目 给定一个整数数组,判断是否存在重复元素。如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。 示例 示例 1:输入: [1,2,3,1]输出: true示例 2:输入: [1,2,3,4]输出: false示例 3:输入: [1,1,1,3,3,4,3,2,4,2]输出: true class Solution {p

剑指offer(C++)--数组中只出现一次的数字

题目 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 class Solution {public:void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {int len = data.size();if(len<2)return;int one = 0;for(int i

设置Nginx缓存策略

详细信息 Nginx服务器的缓存策略设置方法有两种:add_header或者expires。 1. add_header 1)语法:add_header name value。 2)默认值:none。 3)使用范围:http、server、location。 配置示例如下: add_header cache-control "max-age=86400";#设置缓存时间为1天。add

IOS 数组去重的几种方式

本来只知道NSSet和KeyValues的。今天又新学了几种方式 还有就是和同事学的一种方式 外层循环从0开始遍历,内层从最后一个元素开始遍历 for(int i=0;i<index;i++){  for(int j=index-1;j>i;j-- ){ } }

第三十七章 添加和使用自定义标题元素 - 自定义标头的继承

文章目录 第三十七章 添加和使用自定义标题元素 - 自定义标头的继承自定义标头的继承示例 在 `SOAPHEADERS` 参数中指定支持的标头元素自定义标头的继承 第三十七章 添加和使用自定义标题元素 - 自定义标头的继承 自定义标头的继承 如果创建此Web 服务的子类,该子类将继承不特定于方法的标头信息 — 包含在 <request> 或 <response> 元素中的标头信

Java基础(二)——数组,方法,方法重载

个人简介 👀个人主页: 前端杂货铺 ⚡开源项目: rich-vue3 (基于 Vue3 + TS + Pinia + Element Plus + Spring全家桶 + MySQL) 🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步至千里,积小流成江海 🥇推荐学习:🍖开源 rich-vue3 🍍前端面试

【MyBatis学习7】MyBatis中的一级缓存

缓存的作用是减轻数据库的压力,提高数据库的性能的。mybatis中提供了一级缓存和二级缓存,先来看一下两个缓存的示意图:    从图中可以看出: 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。二级缓存是mappe

java NIO 缓存区之内核空间、用户空间和虚拟地址

IO是基于缓存区来做的,所谓的输入和输出就是从缓存区中移入和移出数据。以IO输入为例,首先是用户空间进程向内核请求某个磁盘空间数据,然后内核将磁盘数据读取到内核空间的buffer中,然后用户空间的进程再将内核空间buffer中的数据读取到自身的buffer中,然后进程就可以访问使用这些数据。     内核空间是指操作系统内核运行的空间,是为了保证操作系统内核的能够安全稳定地运行而为内核专

关于修改计算机的处理器数和最大内存数的问题

问题描述: 刚开始本来是想让计算机的运行速度运行的快点,于是在网上搜索如何让计算机的运行速度更快,找到了一种关于修改计算机内存数和计算机的处理核数可以让计算机运行的更快。 遇到问题: 当我通过命令msconfig →引导→高级选项→勾选了处理器数和最大内存数,然后重启,结构整个计算机都卡的要死,于是记录下来。网上的答案有时候真的是很不负责任,也有可能是自己技术不到位。 结果:取消处理器和内