当前位置: 首页 > article >正文

剑指 Offer II 031. 最近最少使用缓存


comments: true
edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20031.%20%E6%9C%80%E8%BF%91%E6%9C%80%E5%B0%91%E4%BD%BF%E7%94%A8%E7%BC%93%E5%AD%98/README.md

剑指 Offer II 031. 最近最少使用缓存

题目描述

运用所掌握的数据结构,设计和实现一个  LRU (Least Recently Used,最近最少使用) 缓存机制 。

实现 LRUCache 类:

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

 

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

 

提示:

  • 1 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 105
  • 最多调用 2 * 105getput

 

进阶:是否可以在 O(1) 时间复杂度内完成这两种操作?

 

注意:本题与主站 146 题相同:https://leetcode.cn/problems/lru-cache/ 

解法

方法一:哈希表 + 双向链表

我们可以用“哈希表”和“双向链表”实现一个 LRU 缓存。

  • 哈希表:用于存储 key 和对应的节点位置。
    - 双向链表:用于存储节点数据,按照访问时间排序。o(1)

当访问一个节点时,如果节点存在,我们将其从原来的位置删除,并重新插入到链表头部。这样就能保证链表尾部存储的就是最近最久未使用的节点,当节点数量大于缓存最大空间时就淘汰链表尾部的节点。

当插入一个节点时,如果节点存在,我们将其从原来的位置删除,并重新插入到链表头部。如果不存在,我们首先检查缓存是否已满,如果已满,则删除链表尾部的节点,将新的节点插入链表头部。

时间复杂度 O ( 1 ) O(1) O(1),空间复杂度 O ( c a p a c i t y ) O(capacity) O(capacity)

Python3
class Node:def __init__(self,key=0,val=0):self.key=keyself.val=valself.prev=Noneself.next=Noneclass LRUCache:def __init__(self, capacity: int):self.cache={}self.capacity=capacity#重要标记: 方便o(1)插入首尾,达到 (链头:最近 链位:最久)self.head=Node()self.tail=Node()self.head.next=self.tailself.tail.prev=self.headself.len=0def get(self, key: int) -> int:if key not in self.cache:return -1Nd=self.cache[key]self.exist_to_head(Nd)return Nd.valdef put(self, key: int, value: int) -> None:if key in self.cache:Nd=self.cache[key]Nd.val=valueself.exist_to_head(Nd)else:Nd=Node(key,value)self.put_to_head(Nd)self.len+=1self.cache[key]=Ndif self.len>self.capacity: #注意1位置:先增后删的意义!!!Nd=self.del_tail()self.len-=1del self.cache[Nd.key]def put_to_head(self,node):node.next=self.head.nextnode.prev=self.headnode.next.prev=nodeself.head.next=nodedef del_tail(self):del_node=self.tail.prevprv_node=del_node.prevprv_node.next=self.tailself.tail.prev=prv_nodereturn del_nodedef exist_to_head(self,node):#先 delprv_node=node.prevnx_node=node.nextprv_node.next=nx_nodenx_node.prev=prv_node#再 put_to_headself.put_to_head(node)# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
Java
class Node {int key;int val;Node prev;Node next;Node() {}Node(int key, int val) {this.key = key;this.val = val;}
}class LRUCache {private Map<Integer, Node> cache = new HashMap<>();private Node head = new Node();private Node tail = new Node();private int capacity;private int size;public LRUCache(int capacity) {this.capacity = capacity;head.next = tail;tail.prev = head;}public int get(int key) {if (!cache.containsKey(key)) {return -1;}Node node = cache.get(key);moveToHead(node);return node.val;}public void put(int key, int value) {if (cache.containsKey(key)) {Node node = cache.get(key);node.val = value;moveToHead(node);} else {Node node = new Node(key, value);cache.put(key, node);addToHead(node);++size;if (size > capacity) {node = removeTail();cache.remove(node.key);--size;}}}private void moveToHead(Node node) {removeNode(node);addToHead(node);}private void removeNode(Node node) {node.prev.next = node.next;node.next.prev = node.prev;}private void addToHead(Node node) {node.next = head.next;node.prev = head;head.next = node;node.next.prev = node;}private Node removeTail() {Node node = tail.prev;removeNode(node);return node;}
}/*** Your LRUCache object will be instantiated and called as such:* LRUCache obj = new LRUCache(capacity);* int param_1 = obj.get(key);* obj.put(key,value);*/
C++
struct Node {int k;int v;Node* prev;Node* next;Node(): k(0), v(0), prev(nullptr), next(nullptr) {}Node(int key, int val): k(key), v(val), prev(nullptr), next(nullptr) {}
};class LRUCache {
public:LRUCache(int capacity): cap(capacity), size(0) {head = new Node();tail = new Node();head->next = tail;tail->prev = head;}int get(int key) {if (!cache.count(key)) return -1;Node* node = cache[key];moveToHead(node);return node->v;}void put(int key, int value) {if (cache.count(key)) {Node* node = cache[key];node->v = value;moveToHead(node);} else {Node* node = new Node(key, value);cache[key] = node;addToHead(node);++size;if (size > cap) {node = removeTail();cache.erase(node->k);--size;}}}private:unordered_map<int, Node*> cache;Node* head;Node* tail;int cap;int size;void moveToHead(Node* node) {removeNode(node);addToHead(node);}void removeNode(Node* node) {node->prev->next = node->next;node->next->prev = node->prev;}void addToHead(Node* node) {node->next = head->next;node->prev = head;head->next = node;node->next->prev = node;}Node* removeTail() {Node* node = tail->prev;removeNode(node);return node;}
};/*** Your LRUCache object will be instantiated and called as such:* LRUCache* obj = new LRUCache(capacity);* int param_1 = obj->get(key);* obj->put(key,value);*/
Go
type node struct {key, val   intprev, next *node
}type LRUCache struct {capacity   intcache      map[int]*nodehead, tail *node
}func Constructor(capacity int) LRUCache {head := new(node)tail := new(node)head.next = tailtail.prev = headreturn LRUCache{capacity: capacity,cache:    make(map[int]*node, capacity),head:     head,tail:     tail,}
}func (this *LRUCache) Get(key int) int {n, ok := this.cache[key]if !ok {return -1}this.moveToFront(n)return n.val
}func (this *LRUCache) Put(key int, value int) {n, ok := this.cache[key]if ok {n.val = valuethis.moveToFront(n)return}if len(this.cache) == this.capacity {back := this.tail.prevthis.remove(back)delete(this.cache, back.key)}n = &node{key: key, val: value}this.pushFront(n)this.cache[key] = n
}func (this *LRUCache) moveToFront(n *node) {this.remove(n)this.pushFront(n)
}func (this *LRUCache) remove(n *node) {n.prev.next = n.nextn.next.prev = n.prevn.prev = niln.next = nil
}func (this *LRUCache) pushFront(n *node) {n.prev = this.headn.next = this.head.nextthis.head.next.prev = nthis.head.next = n
}
TypeScript
class LRUCache {capacity: number;map: Map<number, number>;constructor(capacity: number) {this.capacity = capacity;this.map = new Map();}get(key: number): number {if (this.map.has(key)) {const val = this.map.get(key)!;this.map.delete(key);this.map.set(key, val);return val;}return -1;}put(key: number, value: number): void {this.map.delete(key);this.map.set(key, value);if (this.map.size > this.capacity) {this.map.delete(this.map.keys().next().value);}}
}/*** Your LRUCache object will be instantiated and called as such:* var obj = new LRUCache(capacity)* var param_1 = obj.get(key)* obj.put(key,value)*/
Rust
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;struct Node {key: i32,value: i32,prev: Option<Rc<RefCell<Node>>>,next: Option<Rc<RefCell<Node>>>,
}impl Node {#[inline]fn new(key: i32, value: i32) -> Self {Self {key,value,prev: None,next: None,}}
}struct LRUCache {capacity: usize,cache: HashMap<i32, Rc<RefCell<Node>>>,head: Option<Rc<RefCell<Node>>>,tail: Option<Rc<RefCell<Node>>>,
}/*** `&self` means the method takes an immutable reference.* If you need a mutable reference, change it to `&mut self` instead.*/
impl LRUCache {fn new(capacity: i32) -> Self {Self {capacity: capacity as usize,cache: HashMap::new(),head: None,tail: None,}}fn get(&mut self, key: i32) -> i32 {match self.cache.get(&key) {Some(node) => {let node = Rc::clone(node);self.remove(&node);self.push_front(&node);let value = node.borrow().value;value}None => -1,}}fn put(&mut self, key: i32, value: i32) {match self.cache.get(&key) {Some(node) => {let node = Rc::clone(node);node.borrow_mut().value = value;self.remove(&node);self.push_front(&node);}None => {let node = Rc::new(RefCell::new(Node::new(key, value)));self.cache.insert(key, Rc::clone(&node));self.push_front(&node);if self.cache.len() > self.capacity {let back_key = self.pop_back().unwrap().borrow().key;self.cache.remove(&back_key);}}};}fn push_front(&mut self, node: &Rc<RefCell<Node>>) {match self.head.take() {Some(head) => {head.borrow_mut().prev = Some(Rc::clone(node));node.borrow_mut().prev = None;node.borrow_mut().next = Some(head);self.head = Some(Rc::clone(node));}None => {self.head = Some(Rc::clone(node));self.tail = Some(Rc::clone(node));}};}fn remove(&mut self, node: &Rc<RefCell<Node>>) {match (node.borrow().prev.as_ref(), node.borrow().next.as_ref()) {(None, None) => {self.head = None;self.tail = None;}(None, Some(next)) => {self.head = Some(Rc::clone(next));next.borrow_mut().prev = None;}(Some(prev), None) => {self.tail = Some(Rc::clone(prev));prev.borrow_mut().next = None;}(Some(prev), Some(next)) => {next.borrow_mut().prev = Some(Rc::clone(prev));prev.borrow_mut().next = Some(Rc::clone(next));}};}fn pop_back(&mut self) -> Option<Rc<RefCell<Node>>> {match self.tail.take() {Some(tail) => {self.remove(&tail);Some(tail)}None => None,}}
}
C#
public class LRUCache {class Node {public Node Prev;public Node Next;public int Key;public int Val;}private Node head = new Node();private Node tail = new Node();private Dictionary<int, Node> cache = new Dictionary<int, Node>();private readonly int capacity;private int size;public LRUCache(int capacity) {this.capacity = capacity;head.Next = tail;tail.Prev = head;}public int Get(int key) {Node node;if (cache.TryGetValue(key, out node)) {moveToHead(node);return node.Val;}return -1;}public void Put(int key, int Val) {Node node;if (cache.TryGetValue(key, out node)) {moveToHead(node);node.Val = Val;} else {node = new Node() { Key = key, Val = Val };cache.Add(key, node);addToHead(node);if (++size > capacity) {node = removeTail();cache.Remove(node.Key);--size;}}}private void moveToHead(Node node) {removeNode(node);addToHead(node);}private void removeNode(Node node) {node.Prev.Next = node.Next;node.Next.Prev = node.Prev;}private void addToHead(Node node) {node.Next = head.Next;node.Prev = head;head.Next = node;node.Next.Prev = node;}private Node removeTail() {Node node = tail.Prev;removeNode(node);return node;}
}/*** Your LRUCache object will be instantiated and called as such:* LRUCache obj = new LRUCache(capacity);* int param_1 = obj.Get(key);* obj.Put(key,Val);*/
Swift
class Node {var key: Intvar val: Intvar prev: Node?var next: Node?init() {self.key = 0self.val = 0}init(_ key: Int, _ val: Int) {self.key = keyself.val = val}
}class LRUCache {private var cache = [Int: Node]()private let head: Nodeprivate let tail: Nodeprivate let capacity: Intprivate var size: Intinit(_ capacity: Int) {self.capacity = capacityself.size = 0self.head = Node()self.tail = Node()head.next = tailtail.prev = head}func get(_ key: Int) -> Int {guard let node = cache[key] else {return -1}moveToHead(node)return node.val}func put(_ key: Int, _ value: Int) {if let node = cache[key] {node.val = valuemoveToHead(node)} else {let newNode = Node(key, value)cache[key] = newNodeaddToHead(newNode)size += 1if size > capacity {let tail = removeTail()cache.removeValue(forKey: tail.key)size -= 1}}}private func moveToHead(_ node: Node) {removeNode(node)addToHead(node)}private func removeNode(_ node: Node) {node.prev?.next = node.nextnode.next?.prev = node.prev}private func addToHead(_ node: Node) {node.next = head.nextnode.prev = headhead.next?.prev = nodehead.next = node}private func removeTail() -> Node {let node = tail.prev!removeNode(node)return node}
}/*** Your LRUCache object will be instantiated and called as such:* let obj = LRUCache(capacity)* let ret_1: Int = obj.get(key)* obj.put(key, value)*/

相关文章:

剑指 Offer II 031. 最近最少使用缓存

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20031.%20%E6%9C%80%E8%BF%91%E6%9C%80%E5%B0%91%E4%BD%BF%E7%94%A8%E7%BC%93%E5%AD%98/README.md 剑指 Offer II 031. 最近最少使用缓存 题目描述 运用所掌握的…...

Windows 11【1001问】查看Windows 11 版本的18种方法

随着技术的飞速发展&#xff0c;操作系统作为连接硬件与软件的核心桥梁&#xff0c;其版本管理和更新变得尤为重要。对于用户而言&#xff0c;了解自己设备上运行的具体Windows 11版本不仅有助于优化系统性能&#xff0c;还能确保安全性和兼容性。然而&#xff0c;不同场景和需…...

小程序性能优化-预加载

在微信小程序中&#xff0c;数据预加载是提升用户体验的重要优化手段。以下是处理数据预加载的完整方案&#xff1a; 一、预加载的适用场景 跳转页面前的数据准备 如从列表页进入详情页前&#xff0c;提前加载详情数据首屏加载后的空闲时间 在首页加载完成后&#xff0c;预加载…...

vue3中展示markdown格式文章的三种形式

一、安装 # 使用 npm npm i kangc/v-md-editor -S# 使用yarn yarn add kangc/v-md-editor二、三种实现形式 1、编辑器的只读模式 main.ts文件中配置&#xff1a; import VMdEditor from kangc/v-md-editor; import kangc/v-md-editor/lib/style/base-editor.css;const app …...

(视频教程)Compass代谢分析详细流程及python版-R语言版下游分析和可视化

不想做太多的前情解说了&#xff0c;有点累了&#xff0c;做了很久的内容&#xff0c;包括整个分析&#xff0c;从软件安装和报错解决到后期下游python版-R语言版下游分析和可视化&#xff01;单细胞代谢分析我们写过很多了&#xff0c;唯独少了最“高级”的compass&#xff0c…...

文件描述符与重定向

1. open系统调用 在 Linux 中, open() 系统调用用于打开一个文件或设备&#xff0c;并返回一个文件描述符&#xff0c;通过该描述符可以进行文件读写操作。open() 可以用于创建新文件或打开已存在的文件&#xff0c;具体行为取决于传递给它的参数。 需要包含的头文件&#xf…...

为什么深度学习选择Tensor而非NumPy数组?核心优势深度解析

简短总结&#xff1a; 支持 GPU 加速&#xff1a;Tensor 提供对 GPU 的原生支持&#xff0c;能够有效加速计算&#xff0c;而 NumPy 则通常只能在 CPU 上运行。支持自动求导&#xff1a;深度学习模型的训练依赖于参数的优化&#xff0c;而 Tensor 提供了自动求导功能&#xff…...

python把html网页转换成pdf标题没有乱码,正文都乱码

在使用Python将HTML网页转换成PDF时&#xff0c;遇到标题没有乱码但正文乱码的问题&#xff0c;通常是由于字符编码处理不当或字体支持问题导致的。以下是一些可能的原因和解决方案&#xff1a; 原因分析 字符编码不匹配&#xff1a; HTML文件的编码与PDF转换工具或库所使用的…...

基于fast-whisper模型的语音识别工具的设计与实现

目录 摘 要 第1章 绪 论 1.1 论文研究主要内容 1.1.1模型类型选择 1.1.2开发语言的选择 1.2 国内外现状 第2章 关键技术介绍 2.1 关键性开发技术的介绍 2.1.1 Faster-Whisper数据模型 2.1.2 Django 第3章 系统分析 3.1 构架概述 3.1.1 功能构架 3.1.2 模块需求描述 3.2 系统开…...

详解:事务注解 @Transactional

创作内容丰富的干货文章很费心力&#xff0c;感谢点过此文章的读者&#xff0c;点一个关注鼓励一下作者&#xff0c;激励他分享更多的精彩好文&#xff0c;谢谢大家&#xff01; Transactional 是 Spring Framework 中常用的注解之一&#xff0c;它可以被用于管理事务。通过使用…...

场内、场外期权怎么开户?期权佣金是多少?

期权交易需要一定的知识和经验&#xff0c;以有效管理风险和制定策略。 场内期权开户&#xff08;以50ETF为例&#xff09; 场内期权开户的各种方式大差不差&#xff0c;咱们就先以50ETF期权为例子看下。 场内期权开户条件包括&#xff1a; 首先是资金的要求&#xff0c;50万…...

Linux:进程概念

目录 1 冯诺依曼体系 2 操作系统(Operator System) 3 如何理解管理 3.1计算机管理硬件 3.2 管理逻辑图 3.3 怎样管理 4 什么是进程&#xff1f; 5 查看进程 5.1 ps ajx显示所有进程信息 5.2 /proc(内存文件系统) 5.2.1 ls /proc/PID 5.2.2 ls /proc/PID -al ​ 5…...

Rabbit MQ 高频面试题【刷题系列】

文章目录 一、公司生产环境用的什么消息中间件&#xff1f;二、Kafka、ActiveMQ、RabbitMQ、RocketMQ有什么优缺点&#xff1f;三、解耦、异步、削峰是什么&#xff1f;四、消息队列有什么缺点&#xff1f;五、RabbitMQ一般用在什么场景&#xff1f;六、简单说RabbitMQ有哪些角…...

破解密码防线:渗透测试中的密码攻击手法汇总

密码是网络安全中的一道重要防线&#xff0c;然而&#xff0c;若密码策略不严密&#xff0c;往往会为攻击者提供可乘之机。本文将简要介绍渗透测试中关于密码的几种常见攻击思路和手法。 1. 确认使用默认及常见的账号密码 在渗透测试的初期&#xff0c;攻击者通常会尝试使用系…...

大模型在白血病诊疗全流程风险预测与方案制定中的应用研究

目录 一、绪论 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与内容 二、大模型技术与白血病相关知识 2.1 大模型技术原理与特点 2.2 白血病的病理生理与诊疗现状 三、术前风险预测与手术方案制定 3.1 术前数据收集与预处理 3.2 大模型预测术前风险 3.3 根据…...

5-2JVM内存的各种应用

一、堆区&#xff08;Heap&#xff09;——对象实例的存储池 实际应用场景&#xff1a; ​对象实例化&#xff1a;所有通过 new 关键字创建的对象实例均存储在堆中。例如&#xff1a; java Person person new Person(“张三”); // person对象实例分配在堆区1,4,6 ​大对象直…...

【NLP 28、一文速通NLP文本分类任务 —— 深度学习】

目录 一、深度学习 — pipeline 流水线 1.配置文件 config.py Ⅰ、路径相关 Ⅱ、模型相关 Ⅲ、训练相关 2.数据加载 loader.py Ⅰ、类初始化 Ⅱ、加载数据并预处理 Ⅲ、文本编码 Ⅳ、对输入序列截断或填充 Ⅴ、返回数据长度 Ⅵ、返回对应索引位置元素 Ⅶ、加载词表 Ⅷ、封装数据…...

nvidia驱动更新,centos下安装openwebui+ollama(非docker)

查看centos内核版本 uname -a cat /etc/redhat-release下载对应的程序&#xff08;这个是linux64位版本通用的&#xff09; https://cn.download.nvidia.cn/tesla/550.144.03/NVIDIA-Linux-x86_64-550.144.03.run cudnn想办法自己下一下&#xff0c;我这里是12.x和11.x通用的…...

UnrealEngine UE5 可视化 从地球观察火星 金星 土星 运动轨迹

视频参考&#xff1a;https://www.bilibili.com/video/BV1KpXSYdEdo/ 从地球观察土星的运动轨迹 从地球观察火星 轨迹 从地球观察金星的运动轨迹...

蓝桥杯 五子棋对弈

五子棋对弈 问题描述 “在五子棋的对弈中&#xff0c;友谊的小船说翻就翻&#xff1f;” 不&#xff01;对小蓝和小桥来说&#xff0c;五子棋不仅是棋盘上的较量&#xff0c;更是心与心之间的沟通。这两位挚友秉承着"友谊第一&#xff0c;比赛第二"的宗旨&#xff…...

springmvc热点面试题开胃菜

1. Spring MVC的核心组件有哪些&#xff1f;它们的作用是什么&#xff1f; 答案&#xff1a; Spring MVC的核心组件包括以下部分&#xff0c;每个组件都有其特定的作用&#xff1a; DispatcherServlet&#xff1a; 前端控制器&#xff0c;是Spring MVC的核心。它负责接收所有H…...

关于深度学习的一份介绍

在这篇文章中&#xff0c;我将介绍有关深度学习的东西&#xff0c;主要是它与神经网络的关系、目前主要的网络有哪些&#xff0c;以及加深神经网络的意义等。 一、联系 在之前的文章中&#xff0c;我曾介绍过神经网络&#xff0c;而所谓的神经网络其实就是深度学习的一种架构…...

JavaScript系列02-函数深入理解

本文介绍了JavaScript函数相关知识&#xff0c;包括 函数声明与函数表达式 - 解释两者的区别&#xff0c;提升行为&#xff0c;以及使用场景箭头函数特性 - 讲解语法、词法this、不能作为构造函数等特点this绑定机制 - 详细讲解四种绑定规则&#xff1a;默认绑定、隐式绑定、显…...

Netty是怎么实现Java NIO多路复用的?(源码)

目录 NIO多路复用实现事件循环是什么&#xff1f;核心源码&#xff08;1&#xff09;调用 NioEventLoopGroup 默认构造器&#xff08;2&#xff09;指定 SelectorProvider&#xff08;3&#xff09;创建 Selector&#xff08;4&#xff09;创建单线程和队列&#xff08;5&#…...

SourceTree配置SSH步骤详解

1. 生成SSH密钥对 如果尚未生成SSH密钥&#xff0c;需先创建&#xff1a; Windows/macOS/Linux通用方法 打开终端&#xff08;或Git Bash&#xff09;。 输入以下命令&#xff08;替换为你的邮箱&#xff09;&#xff1a; bash 复制 ssh-keygen -t ed25519 -C "your_em…...

Rocky Linux 8.5 6G内存 静默模式(没图形界面)安装Oracle 19C

Oracle19c 下载地址 Database Software Downloads | Oraclehttps://www.oracle.com/database/technologies/oracle-database-software-downloads.html#db_ee 目录 一、准备服务器 1、服务器可以克隆、自己装 2、修改主机名 3、重启 4、关闭selinux 5、关闭防火墙 5.1、…...

免费轻巧多功能 PDF 处理工具:转换、压缩、提取一应俱全

软件技术 今天要给大家分享一款超实用的 PDF 处理工具&#xff0c;它免费又轻巧&#xff0c;如同随时待命的得力小帮手&#xff0c;功能之强大超乎想象&#xff0c;真的值得大家收藏。 这款工具是绿色版软件&#xff0c;解压后开启&#xff0c;满满的 PDF 处理功能便映入眼帘…...

基于ssm的校园跑腿管理系统+vue

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统共有管理员、用户两个角色 管理员主要的功能用户信息管理、任务信息管理、任务类型管理、接单信息管理、公告信息管理、投诉信息管理、公告类型管…...

java数据结构_Map和Set_9.1

1. 搜索树 1.1 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有的结点都小于根结点的值若它的右子树不为空&#xff0c;则右子树上所有的结点都大于根结点的值…...

横向移动靶场-Tr0ll: 3

Tr0ll: 3来自 <Tr0ll: 3 ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182&#xff0c;靶场IP192.168.23.187 3&#xff0c;对靶机进行端口服务探测 …...