dedecms 金融类网站模板,黄冈网站建设推荐,国内大型网站制作,网站制作文案下面给你 可直接在面试中手写的 LRU#xff08;Least Recently Used#xff09;缓存 Java 源代码#xff0c;支持 O(1) put/get#xff0c;基于 HashMap 双向链表。 代码简洁、无多余封装、适合白板面试。 ✔ 手写 LRUCache#xff08;Java 完整代码#xff09;
import…下面给你可直接在面试中手写的 LRULeast Recently Used缓存 Java 源代码支持 O(1) put/get基于HashMap 双向链表。代码简洁、无多余封装、适合白板面试。✔手写 LRUCacheJava 完整代码importjava.util.HashMap;importjava.util.Map;publicclassLRUCache{classNode{intkey,value;Nodeprev,next;publicNode(intk,intv){keyk;valuev;}}privatefinalintcapacity;privatefinalMapInteger,Nodemap;privatefinalNodehead,tail;// 哨兵节点publicLRUCache(intcapacity){this.capacitycapacity;mapnewHashMap();headnewNode(-1,-1);tailnewNode(-1,-1);head.nexttail;tail.prevhead;}publicintget(intkey){if(!map.containsKey(key))return-1;Nodenodemap.get(key);remove(node);insertToHead(node);returnnode.value;}publicvoidput(intkey,intvalue){if(map.containsKey(key)){Nodenodemap.get(key);node.valuevalue;remove(node);insertToHead(node);}else{if(map.size()capacity){Nodelasttail.prev;remove(last);map.remove(last.key);}NodenewNodenewNode(key,value);insertToHead(newNode);map.put(key,newNode);}}privatevoidremove(Nodenode){node.prev.nextnode.next;node.next.prevnode.prev;}privatevoidinsertToHead(Nodenode){node.nexthead.next;head.next.prevnode;node.prevhead;head.nextnode;}}关键点说明适合面试说数据结构作用HashMapInteger, Node根据 key O(1) 查找 Node双向链表 Node维护访问顺序头部是最新尾部是最旧Head/Tail 哨兵节点避免大量空指针判断 时间复杂度操作复杂度get / putO(1)delete / moveO(1) 你可以在面试中这么总结LRU 需要 O(1) 的删除和插入操作所以必须使用 HashMap 双向链表。Map 用于快速查找节点位置链表用于维护访问时间顺序最新放在头部超过容量时从尾部移除最旧的节点。如需扩展版本支持泛型、线程安全、LinkedHashMap 一行实现回复继续升级版本你需要手写LRU最近最少使用缓存的Java完整源代码我会优先提供面试高频考察的底层实现版本HashMap 双向链表这是手写LRU的核心考点同时补充基于LinkedHashMap的简易版方便你对比理解。一、核心原理说明LRU的核心规则是当缓存容量达到上限时移除最近最少使用的元素get/put操作会将元素标记为「最近使用」。用HashMap实现O(1)时间复杂度的节点查找用双向链表维护元素的访问顺序头节点最近使用尾节点最久未使用核心操作get查移到头部、put增/更移到头部超容则删尾节点。二、底层实现版HashMap 双向链表这是面试手写的标准版本无依赖JDK高级封装能体现底层逻辑理解importjava.util.HashMap;importjava.util.Map;/** * 手写LRU缓存基于HashMap 双向链表实现 * 核心O(1)查找HashMap O(1)增删双向链表 */publicclassLRUCache{// 双向链表节点类存储keyvalue以及前后指针staticclassDNode{intkey;intvalue;DNodeprev;DNodenext;publicDNode(){}publicDNode(intkey,intvalue){this.keykey;this.valuevalue;}}// 缓存容量privateintcapacity;// 实际存储的元素数量privateintsize;// HashMap快速定位节点key缓存keyvalue链表节点privateMapInteger,DNodecacheMap;// 双向链表的伪头/伪尾避免空指针判断简化操作privateDNodehead;privateDNodetail;// 构造方法初始化容量、HashMap、双向链表头尾publicLRUCache(intcapacity){this.capacitycapacity;this.size0;this.cacheMapnewHashMap();// 初始化伪头、伪尾且相互指向headnewDNode();tailnewDNode();head.nexttail;tail.prevhead;}/** * 获取缓存值O(1) * param key 缓存key * return 存在则返回value否则返回-1 */publicintget(intkey){DNodenodecacheMap.get(key);if(nodenull){return-1;}// 访问后将节点移到「最近使用」的头部moveToHead(node);returnnode.value;}/** * 存入缓存O(1) * param key 缓存key * param value 缓存value */publicvoidput(intkey,intvalue){DNodenodecacheMap.get(key);if(nodenull){// 1. 新节点创建加入HashMap加入链表头部DNodenewNodenewDNode(key,value);cacheMap.put(key,newNode);addToHead(newNode);size;// 2. 超容量移除「最久未使用」的尾节点同时删除HashMap中的记录if(sizecapacity){DNodetailNoderemoveTail();cacheMap.remove(tailNode.key);size--;}}else{// 已有节点更新value 移到头部标记为最近使用node.valuevalue;moveToHead(node);}}// 双向链表辅助方法 /** * 将节点添加到链表头部伪头之后 */privatevoidaddToHead(DNodenode){node.prevhead;node.nexthead.next;head.next.prevnode;head.nextnode;}/** * 移除指定节点 */privatevoidremoveNode(DNodenode){node.prev.nextnode.next;node.next.prevnode.prev;}/** * 将节点移到头部先移除再添加到头部 */privatevoidmoveToHead(DNodenode){removeNode(node);addToHead(node);}/** * 移除最久未使用的尾节点伪尾之前的节点 */privateDNoderemoveTail(){DNoderealTailtail.prev;removeNode(realTail);returnrealTail;}// 测试用例publicstaticvoidmain(String[]args){LRUCachelruCachenewLRUCache(2);lruCache.put(1,1);// 缓存{11}lruCache.put(2,2);// 缓存{11, 22}System.out.println(lruCache.get(1));// 输出1缓存{22, 11}1移到头部lruCache.put(3,3);// 容量超2移除最久未使用的2缓存{11, 33}System.out.println(lruCache.get(2));// 输出-1已被移除lruCache.put(4,4);// 容量超2移除最久未使用的1缓存{33, 44}System.out.println(lruCache.get(1));// 输出-1已被移除System.out.println(lruCache.get(3));// 输出3缓存{44, 33}System.out.println(lruCache.get(4));// 输出4缓存{33, 44}}}三、关键代码解释双向链表节点DNode存储key移除尾节点时需要通过key删除HashMap中的记录、valueprev/next前后指针实现O(1)时间的节点增删。伪头/伪尾head/tail避免处理「头节点为空」「尾节点为空」的边界情况简化代码逻辑。核心方法get查不到返回-1查到则移到头部标记为最近使用put新节点创建→加HashMap→加链表头部→超容则删尾节点同步删HashMap已有节点更新value→移到头部辅助方法addToHead加头部、removeNode删节点、moveToHead移头部、removeTail删尾节点。四、简易版基于LinkedHashMapJDK的LinkedHashMap天然支持按访问顺序排序只需重写removeEldestEntry即可实现LRU适合工程开发但面试手写不推荐体现不出底层能力importjava.util.LinkedHashMap;importjava.util.Map;publicclassLRUCacheSimpleextendsLinkedHashMapInteger,Integer{privateintcapacity;publicLRUCacheSimple(intcapacity){// 初始化初始容量capacity负载因子0.75按访问顺序排序第三个参数truesuper(capacity,0.75f,true);this.capacitycapacity;}publicintget(intkey){// 父类get方法会自动将节点移到「最近使用」位置returnsuper.getOrDefault(key,-1);}publicvoidput(intkey,intvalue){super.put(key,value);}/** * 重写该方法当元素数量超过容量时移除最久未使用的元素 */OverrideprotectedbooleanremoveEldestEntry(Map.EntryInteger,Integereldest){returnsize()capacity;}// 测试用例和底层版一致publicstaticvoidmain(String[]args){LRUCacheSimplelrunewLRUCacheSimple(2);lru.put(1,1);lru.put(2,2);System.out.println(lru.get(1));// 1lru.put(3,3);System.out.println(lru.get(2));// -1lru.put(4,4);System.out.println(lru.get(1));// -1System.out.println(lru.get(3));// 3System.out.println(lru.get(4));// 4}}总结面试手写LRU优先选HashMap 双向链表实现核心是「O(1)查找 O(1)增删」双向链表需维护「伪头/伪尾」简化边界处理节点必须存key删尾节点时同步删HashMapget/put操作都要将节点移到头部超容时删除尾节点最久未使用。下一步迭代建议需要我为你分析这个LRU实现的时间/空间复杂度以及面试中可能被追问的「线程安全优化方案」吗下面是一个「简单版」的 LRU 缓存实现只用到基础数据结构一个HashMapK, NodeK,VO(1) 查找 key 对应节点一个自定义的双向链表O(1) 把节点移动到头部 / 删除尾部这里的 LRU 语义get(key)如果存在返回值并把节点移动到链表头部最近使用。put(key, value)如果 key 已存在更新值并移动到头部如果 key 不存在新建节点插入头部如果容量已满删除尾部节点最久未使用importjava.util.HashMap;importjava.util.Map;/** * 简单版 LRU Cache 手写实现不依赖 LinkedHashMap * 特点 * - get/put 均为 O(1) * - 使用 HashMap 双向链表 */publicclassLRUCacheK,V{// 双向链表节点privatestaticclassNodeK,V{Kkey;Vvalue;NodeK,Vprev;NodeK,Vnext;Node(){}Node(Kkey,Vvalue){this.keykey;this.valuevalue;}}privatefinalintcapacity;privatefinalMapK,NodeK,Vmap;// 虚拟头尾节点方便处理边界privatefinalNodeK,Vhead;privatefinalNodeK,Vtail;publicLRUCache(intcapacity){if(capacity0){thrownewIllegalArgumentException(capacity must be 0);}this.capacitycapacity;this.mapnewHashMap();this.headnewNode();this.tailnewNode();head.nexttail;tail.prevhead;}/** * 获取缓存中的值如果不存在返回 null。 * 同时将访问的节点移动到链表头部最近使用 */publicVget(Kkey){NodeK,Vnodemap.get(key);if(nodenull){returnnull;}moveToHead(node);returnnode.value;}/** * 放入 key-value。 * 如果 key 已存在更新 value并移动到头部 * 如果 key 不存在新建节点插入头部如果超出容量删除尾部节点。 */publicvoidput(Kkey,Vvalue){NodeK,Vnodemap.get(key);if(node!null){// 已存在更新值并移动到头部node.valuevalue;moveToHead(node);}else{// 新节点NodeK,VnewNodenewNode(key,value);map.put(key,newNode);addToHead(newNode);// 超出容量移除尾部节点if(map.size()capacity){NodeK,VtailNoderemoveTail();if(tailNode!null){map.remove(tailNode.key);}}}}// 将节点移动到双向链表头部privatevoidmoveToHead(NodeK,Vnode){removeNode(node);addToHead(node);}// 在链表头部插入节点head 之后privatevoidaddToHead(NodeK,Vnode){node.prevhead;node.nexthead.next;head.next.prevnode;head.nextnode;}// 从链表中移除节点privatevoidremoveNode(NodeK,Vnode){NodeK,Vprevnode.prev;NodeK,Vnextnode.next;prev.nextnext;next.prevprev;}// 移除尾部真实数据节点tail 前一个并返回之privateNodeK,VremoveTail(){NodeK,Vnodetail.prev;if(nodehead){returnnull;}removeNode(node);returnnode;}// 简单测试publicstaticvoidmain(String[]args){LRUCacheInteger,StringcachenewLRUCache(2);cache.put(1,one);cache.put(2,two);System.out.println(cache.get(1));// one1 变为最近使用cache.put(3,three);// 淘汰 key2System.out.println(cache.get(2));// nullcache.put(4,four);// 淘汰 key1System.out.println(cache.get(1));// nullSystem.out.println(cache.get(3));// threeSystem.out.println(cache.get(4));// four}}如果你需要线程安全版本基于LinkedHashMap的简化实现或者带过期时间/统计信息的 LRU可以告诉我具体需求我再给对应代码。根据真实的面经和笔经我为你整理了一份同花顺后端/大数据工程师岗位的高频面试考题与核心回答思路以便你更有针对性地准备。下面将面试考核分为三个主要部分技术一面、技术二面和笔试。 技术一面 - 基础与算法这一轮主要考察你的技术基本功、项目经验和编码能力。类别高频考题核心回答思路必过要点Java基础sleep和wait方法的区别。重载(Overload)和重写(Override)的区别。final,finally,finalize的区别。sleep vs waitsleep是Thread的静态方法不释放锁用于计时等待wait是Object的方法必须在同步块中调用并释放锁用于线程间协作。重载 vs 重写重载是编译时多态同一类中方法名相同、参数列表不同重写是运行时多态子类重写父类方法方法签名相同。数据库MySQL的引擎有哪些Spring的注解有哪些MySQL引擎至少说出InnoDB支持事务、行级锁、外键和MyISAM不支持事务、表级锁、适合读多写少的主要区别和适用场景。并发编程线程间通信方式有哪些要能说出几种核心方式1. 共享内存通过volatile变量等2. 等待/通知机制wait()/notify()3. 管道流PipedInputStream/PipedOutputStream4. 使用Lock和Condition。算法与编码一次遍历找出未排序数组中第一和第二大的元素。手写LRU缓存。找最大和次大使用两个变量max1,max2遍历数组。遇到比max1大的先更新max2max1再更新max1否则只与max2比较更新。这是O(n)解法。手写LRU结合哈希表快速定位和双向链表维护访问顺序实现get和put操作保证时间复杂度为O(1)。Linux与项目说几个你知道的Linux命令。讲自己做得不错的项目。Linux命令准备文件操作cat,grep,awk,sed、进程管理ps,top,kill、网络netstat,ss等常用命令。项目介绍使用STAR法则情境、任务、行动、结果重点突出技术难点、你的具体贡献和量化成果。 技术二面 - 深度与设计这一轮问题更深考察你的理解深度和系统设计能力。类别高频考题核心回答思路必过要点集合框架HashMap的底层原理、扩容机制期望容量为7实际容量是多少原理数组链表/红黑树。讲清楚put过程哈希计算、解决冲突、链表转树和扩容机制负载因子0.75扩容为2倍并重新散列。容量计算HashMap容量是2的幂。tableSizeFor()方法会找到大于等于给定值的最小2的幂。所以容量是8。并发进阶线程池核心参数和工作原理如何中断一个线程线程池参数核心线程数、最大线程数、工作队列、线程工厂、拒绝策略。工作原理任务先提交给核心线程核心满则入队队满且线程未达最大则创建新线程都满则触发拒绝策略。中断线程调用线程的interrupt()方法它只是设置一个中断标志。被中断的线程需要检查Thread.interrupted()状态并做出响应。设计模式与框架单例模式有几种写法双重校验锁为何要加volatileAOP是什么和过滤器有什么区别单例模式至少掌握饿汉式、懒汉式含双重检查锁、静态内部类、枚举四种。volatile防止指令重排保证对象初始化的完整性。AOP vs 过滤器AOP是面向切面编程主要在业务层拦截方法执行用于日志、事务等。过滤器是Servlet规范在请求前后过滤HTTP请求和响应更底层用于编码转换、安全过滤等。系统设计设计一个“订单15分钟后超时取消”的功能核心思路1.延迟消息使用RocketMQ/Kafka的延迟消息或Redis的键过期通知非绝对可靠。2.定时扫描将订单入库设置状态和到期时间后台定时任务扫描待处理的超时订单需考虑分页和效率。3.时间轮算法高效处理大量定时任务。通常结合数据库持久化延迟消息兜底扫描来保证可靠性。大数据场景遇到运行很久不出结果的任务如何优化分层排查1.数据层检查数据倾斜某个Key数据量极大解决方案如加盐打散、两阶段聚合。2.计算层检查SQL/代码逻辑是否复杂能否优化调整并行度。3.资源层查看CPU/内存是否不足申请更多资源。4.存储层检查数据格式如Parquet/ORC是否比TextFile更高效。 笔试 - 广度与思维同花顺的笔试通常题量较大题型多样。类别高频考题核心回答思路必过要点计算机基础IO阻塞与非阻塞的区别。多进程与多线程的区别与应用场景。为什么0.10.2!0.3IO模型阻塞IO会一直等待数据就绪非阻塞IO会立即返回通过轮询等方式检查。进程vs线程进程资源独立切换开销大线程共享进程资源切换开销小。频繁创建销毁、强相关计算用线程需要高稳定性、弱相关用进程。浮点数精度十进制小数转二进制时可能出现无限循环导致精度丢失。这是IEEE 754标准的固有局限。网络与安全TCP通信为什么会丢数据对称加密与非对称加密的区别。服务器被攻击如何排查伪装成正常程序的恶意软件TCP丢包网络拥塞、校验和错误、接收方缓冲区满等都可能导致。粘包是数据组织问题不是丢失。加密方式对称加密加解密密钥相同如AES速度快非对称加密有公钥/私钥对如RSA用于密钥交换和签名。安全排查检查异常网络连接netstat、进程ps、文件修改时间和系统日志使用rkhunter等工具查杀从干净备份恢复。编程与SQL对象锁和类锁的区别。匹配URL的正则表达式。手写算法或复杂SQL。对象锁 vs 类锁对象锁锁的是具体实例不同实例互不干扰类锁锁的是整个类的Class对象所有实例互斥。正则表达式例如^(https?://)?([\da-z\.-])\.([a-z\.]{2,6})([/\w \.-]*)*/?$能匹配常见HTTP/HTTPS URL。✨ 针对性面试策略除了准备好具体答案掌握策略同样关键展示金融业务思维在回答系统设计或大数据优化问题时尝试联系金融场景如实时行情、交易风控、用户画像这是同花顺非常看重的。体现深度和广度二面的问题如HashMap扩容、AQS需要理解底层原理。主动提及相关机制如synchronized锁升级、volatile内存屏障能体现你的深度。坦诚沟通积极思考遇到完全不懂的问题可以说“这个领域我了解不深但根据我的理解我认为…”并给出一个解决问题的思路这比生硬回答更好。希望这份详细的考题与思路清单能帮助你高效备考。如果你想针对上述某个高频考点比如“数据倾斜优化”或“订单超时设计”进行更深入的模拟问答练习我可以继续为你详细展开。