Day12–HOT100–23. 合并 K 个升序链表,146. LRU 缓存,94. 二叉树的中序遍历

每日刷题系列。今天的题目是《力扣HOT100》题单。

题目类型:链表,二叉树。

LRU缓存要重点掌握。

23. 合并 K 个升序链表

方法:暴力

思路:

遍历lists的头节点,每次取最小值,移除头结点,直到所有链表都被移除完。

使用nullCount == n控制循环退出。

时间复杂度很高,多少个节点就遍历多少次。

class Solution {public ListNode mergeKLists(ListNode[] lists) {int n = lists.length;// 因为新链表的头不一定,所以需要一个哨兵指向头的前一位ListNode dummy = new ListNode(-1);// 新链表的指针ListNode p = dummy;while (true) {// 使用nullCount == n控制循环退出int nullCount = 0;// 找到链表头是最小值的那个链表int index = 0;int minVal = Integer.MAX_VALUE;for (int i = 0; i < n; i++) {// 记录已经是null的链表if (lists[i] == null) {nullCount++;} else if (lists[i].val < minVal) {minVal = lists[i].val;index = i;}}// 全部链表为空,退出if (nullCount == n) {break;}// 拼接在新链表的尾巴上,p指向下一位p.next = lists[index];p = p.next;// 该链表的头已经被拼走了,指针指向下一位。lists[index] = lists[index].next;}return dummy.next;}
}

方法:小顶堆

思路:

使用小顶堆,每个链表把自己的最小节点放到堆里面去。这样不用每次都遍历一遍。

  1. 准备工作:new一个小顶堆。先遍历第一次,把所有非空链表的头节点入堆
  2. 定义哨兵节点,作为合并后链表头节点的前一个节点——为了找回新的头
  3. 循环直到堆为空
    1. 因为是小顶堆,每次取都是最小值的节点node
    2. 把 node 添加到新链表的末尾
    3. cur指针后移,准备合并下一个节点
    4. 如果该链表还有元素,把该链表的下一个节点入堆。
class Solution {public ListNode mergeKLists(ListNode[] lists) {PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> Integer.compare(a.val, b.val));// 准备工作:先遍历第一次,把所有非空链表的头节点入堆for (ListNode head : lists) {if (head != null) {pq.offer(head);}}// 哨兵节点,作为合并后链表头节点的前一个节点——为了找回新的头ListNode dummy = new ListNode();ListNode cur = dummy;// 循环直到堆为空while (!pq.isEmpty()) {// 因为是小顶堆,每次取都是最小值的节点ListNode node = pq.poll();// 把 node 添加到新链表的末尾cur.next = node;// 指针后移,准备合并下一个节点cur = cur.next;// 如果该链表还有元素,把该链表的下一个节点入堆。if (node.next != null) {pq.offer(node.next);}}return dummy.next;}
}

方法:递归

思路:

分治。两两合并后返回。(来自@灵茶山艾府)

class Solution {public ListNode mergeKLists(ListNode[] lists) {return mergeKLists(lists, 0, lists.length);}// 合并从 lists[i] 到 lists[j-1] 的链表// 这里的ij是左闭右开的private ListNode mergeKLists(ListNode[] lists, int l, int r) {int len = r - l;if (len == 0) {return null; // 注意输入的 lists 可能是空的}if (len == 1) {return lists[l]; // 无需合并,直接返回}ListNode left = mergeKLists(lists, l, l + len / 2); // 合并左半部分ListNode right = mergeKLists(lists, l + len / 2, r); // 合并右半部分return mergeTwoLists(left, right); // 最后把左半和右半合并}// 21. 合并两个有序链表private ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode dummy = new ListNode(); // 用哨兵节点简化代码逻辑ListNode cur = dummy; // cur 指向新链表的末尾while (list1 != null && list2 != null) {if (list1.val < list2.val) {cur.next = list1; // 把 list1 加到新链表中list1 = list1.next;} else { // 注:相等的情况加哪个节点都是可以的cur.next = list2; // 把 list2 加到新链表中list2 = list2.next;}cur = cur.next;}cur.next = list1 != null ? list1 : list2; // 拼接剩余链表return dummy.next;}
}

146. LRU 缓存

思路:

手写LinkedHashMap实现。

使用普通HashMap存储<key,Node>映射关系,手动实现双向链表记录访问顺序。

  • 重点在于维护节点的访问顺序:(也就是维护双向链表)
    • get:先删除节点,再移动到链表的尾端(表示最新访问的key),返回节点。
    • put
      • 如果是新节点,直接put在尾端。
        • 当put达到容量capacity时,删除链表头结点(表示最旧访问的key)
      • 如果是旧节点,map更新value,链表删除节点,再在链表尾端put新节点。
public class LRUCache {class Node {int key;int value;Node prev;Node next;public Node() {}public Node(int key, int value) {this.key = key;this.value = value;}}private Map<Integer, Node> cache;private int size;private int capacity;private Node head, tail;public LRUCache(int capacity) {this.size = 0;this.capacity = capacity;cache = new HashMap<Integer, Node>(capacity);// 伪头部(最久未访问端)和伪尾部(最近访问端),简化边界操作head = new Node();tail = new Node();head.next = tail;tail.prev = head;}public int get(int key) {Node node = cache.get(key);if (node == null) {return -1;}//  key存在:将该节点移到尾部moveToTail(node);return node.value;}public void put(int key, int value) {Node node = cache.get(key);//  key存在:更新value并移到尾部if (node != null) {node.value = value;moveToTail(node);} else {//  key不存在:创建新节点Node newNode = new Node(key, value);cache.put(key, newNode);// 添加到尾部addToTail(newNode);size++;// 容量满时:删除头部(最久未访问端)节点if (size > capacity) {Node removedNode = removeHead();cache.remove(removedNode.key);size--;}}}// 新节点添加到尾部private void addToTail(Node node) {node.prev = tail.prev;node.next = tail;tail.prev.next = node;tail.prev = node;}// 从链表中移除指定节点private void removeNode(Node node) {node.prev.next = node.next;node.next.prev = node.prev;}// 将指定节点移到尾部private void moveToTail(Node node) {// 先从原位置移除节点removeNode(node);// 再添加到尾部addToTail(node);}// 删除头部节点(伪头部的下一个节点)private Node removeHead() {Node removedNode = head.next;removeNode(removedNode);return removedNode;}
}

思路:

直接继承LinkedHashMap实现。

不过面试一般不会这么考察,没什么需要你写的代码了。除了可以展示你对库函数的熟练程度。

class LRUCache extends LinkedHashMap<Integer, Integer>{private int capacity;public LRUCache(int capacity) {// 这里的true,表示开启accessOrder,链表会维护访问顺序// 开启之后,最新访问的值,会移动到最尾端。super(capacity, 0.75F, true);this.capacity = capacity;}public int get(int key) {return super.getOrDefault(key, -1);}public void put(int key, int value) {super.put(key, value);}// 当什么情况下,删除最旧访问节点。默认是返回false,要重写。@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity; }
}

思路:

调用LinkedHashMap实现,写核心逻辑。

  1. get的时候,要先remove原来的,再put进去,这样才会在链表的尾部,才会被视作最新访问的元素
  2. put的时候
    • 情况一:如果原来有这个key,remove掉原来的,put新值,此时key会去到链表尾部。
    • 情况二:如果原来没有这个key。put进去。如果容量超了,把最旧的值remove掉(使用迭代器拿到第一个key)
class LRUCache {private final int capacity;private final Map<Integer, Integer> cache = new LinkedHashMap<>();public LRUCache(int capacity) {this.capacity = capacity;}// 要先remove原来的,再put进去,这样才会在链表的尾部,才会被视作最新访问的元素public int get(int key) {Integer value = cache.get(key);if (value != null) {cache.remove(key);cache.put(key, value);return value;}return -1;}public void put(int key, int value) {// 情况一:如果原来有这个key,remove掉原来的,put新值,此时key会去到链表尾部。if (cache.get(key) != null) {cache.remove(key);cache.put(key, value);return;}// 情况二:如果原来没有这个key// put进去cache.put(key, value);// 如果容量超了,把最旧的值remove掉if (cache.size() > capacity) {// 使用迭代器拿到第一个keyInteger eldestKey = cache.keySet().iterator().next();cache.remove(eldestKey);}}
}

94. 二叉树的中序遍历

方法:迭代

思路:

左中右遍历。

class Solution {private List<Integer> res = new ArrayList<>();public List<Integer> inorderTraversal(TreeNode root) {backtrack(root);return res;}private void backtrack(TreeNode node) {if (node == null) {return;}backtrack(node.left);res.add(node.val);backtrack(node.right);}
}

方法:迭代

思路:

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<>();Deque<TreeNode> stack = new ArrayDeque<>();TreeNode cur = root;while (cur != null || !stack.isEmpty()) {if (cur != null) {stack.push(cur);cur = cur.left;} else {cur = stack.pop();res.add(cur.val);cur = cur.right;}}return res;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:
http://www.pswp.cn/diannao/98149.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98149.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/98149.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode热题100道笔记】二叉树展开为链表

题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序遍历 顺序相同。 示例 …

华为OmniPlacement技术深度解析:突破超大规模MoE模型推理瓶颈的创新设计

MoE模型的崛起与负载均衡挑战 混合专家模型&#xff08;Mixture of Experts&#xff0c;MoE&#xff09;作为大规模深度学习的前沿架构&#xff0c;通过稀疏激活模式成功地将模型参数规模推向了新的高度&#xff0c;同时保持了相对合理的计算成本。其核心思想是使用多个专门的…

分享一个基于Python+大数据的房地产一手房成交数据关联分析与可视化系统,基于机器学习的深圳房产价格走势分析与预测系统

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Spark、hadoop、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题…

【C++题解】DFS和BFS

4小时编码练习计划&#xff0c;专注于深度优先搜索&#xff08;DFS&#xff09;和广度优先搜索&#xff08;BFS&#xff09;这两种基本且强大的算法。 下午 (4小时): 搜索算法专题——DFS与BFS DFS和BFS是图论和多种问题求解中的基石算法。深刻理解它们的原理、差异和代码实现模…

Android模拟简单的网络请求框架Retrofit实现

文章目录1.静态代理2.动态代理3.实现简单的Retrofit定义对应的请求注解参数通过动态代理模拟Retrofit的创建请求参数的处理定义请求接口测试请求1.静态代理 代理默认给某一个对象提供一个代理对象&#xff0c;并由代理对象控制对原对象的引用。通俗来讲&#xff0c;代理模式就…

Matter安全实现

Matter分析与安全验证 上一篇文章简单的介绍了Matter的架构、实现、以及部分安全验证过程&#xff1b;这里继续补充一下Matter的其他安全验证流程&#xff0c;以更好的实现Matter安全。 Matter提供的安全实现流程大概总结起来是这个流程 硬件信任根→安全启动→动态证书→加密…

从基础到实践:Web核心概念与Nginx入门全解析

从基础到实践&#xff1a;Web核心概念与Nginx入门全解析 文章目录从基础到实践&#xff1a;Web核心概念与Nginx入门全解析一、Web是什么&#xff1f;从基本概念到核心架构1.1 Web的本质&#xff1a;一个超文本信息系统1.2 B/S架构&#xff1a;Web的“前端-后端”分工模式二、一…

【完整源码+数据集+部署教程】加工操作安全手套与手部检测系统源码和数据集:改进yolo11-cls

背景意义 研究背景与意义 随着工业自动化和智能制造的迅速发展&#xff0c;工人安全问题日益受到重视。特别是在涉及重型机械和危险操作的工作环境中&#xff0c;工人手部的安全保护显得尤为重要。传统的安全手套虽然在一定程度上能够保护工人的手部&#xff0c;但在复杂的加工…

代码随想录算法训练营第一天 || (双指针)27.移除元素 26.删除有序数组中的重复项 283.移动零 977.有序数组的平方

代码随想录算法训练营第一天 || (双指针)27.移除元素 26.删除有序数组中的重复项 283.移动零 27.移除元素 暴力方法 同向双指针双指针 自己AC的解答 卡哥的讲解 26.删除有序数组中的重复项 同向双指针 283.移动零 自己解答 灵神做法(同向双指针+交换) 977.有序数组的平方 暴…

Java全栈开发工程师面试实录:从基础到实战的深度探讨

Java全栈开发工程师面试实录&#xff1a;从基础到实战的深度探讨 一、初识与自我介绍 面试官&#xff08;李工&#xff09;&#xff1a; 你好&#xff0c;欢迎来到我们公司。我是负责技术面试的李工&#xff0c;今天我们将进行一场关于Java全栈开发的深入交流。你可以先简单介绍…

Kafka:Java开发的消息神器,你真的懂了吗?

Kafka&#xff1a;Java开发的消息神器&#xff0c;你真的懂了吗&#xff1f; 一、Kafka 是什么鬼&#xff1f; 想象一下&#xff0c;你在网上疯狂剁手后&#xff0c;满心期待着快递包裹的到来。这时候&#xff0c;快递站就像是 Kafka&#xff0c;而你的包裹就是消息。快递站接…

深度学习之第八课迁移学习(残差网络ResNet)

目录 简介 一、迁移学习 1.什么是迁移学习 2. 迁移学习的步骤 二、残差网络ResNet 1.了解ResNet 2.ResNet网络---残差结构 三、代码分析 1. 导入必要的库 2. 模型准备&#xff08;迁移学习&#xff09; 3. 数据预处理 4. 自定义数据集类 5. 数据加载器 6. 设备配置…

Pinia 两种写法全解析:Options Store vs Setup Store(含实践与场景对比)

目标&#xff1a;把 Pinia 的两种写法讲透&#xff0c;写明“怎么写、怎么用、怎么选、各自优缺点与典型场景”。全文配完整代码与注意事项&#xff0c;可直接当团队规范参考。一、背景与准备 适用版本&#xff1a;Vue 3 Pinia 2.x安装与初始化&#xff1a; # 安装 npm i pini…

setup函数相关【3】

目录1.setup函数&#xff1a;1.概述&#xff1a;2.案例分析&#xff1a;2.setup函数的优化&#xff1a;&#xff08;setup语法糖&#xff09;优化1&#xff1a;优化2&#xff1a;安装插件&#xff1a;安装指令&#xff1a;只对当前项目安装配置vite.config.ts&#xff1a;代码编…

如何通过AI进行数据资产梳理

最终产出 数据资产清单 包含所有数据资产的详细目录,列出数据集名称、描述、所有者、格式、存储位置和元数据。 用途:帮助政府部门清晰了解数据资产分布和状态。 数据质量报告 数据质量评估结果,记录准确性、完整性、一致性等问题及改进建议,基于政府认可的数据质量框架(如…

【传奇开心果系列】Flet框架结合pillow实现的英文文字倒映特效自定义模板特色和实现原理深度解析

Flet框架结合pillow实现的英文文字倒映特效自定义模板特色和实现原理深度解析 一、效果展示截图 二、使用场景 三、特色说明 四、概括说明 五、依赖文件列表 六、安装依赖命令 七、 项目结构建议 八、注意事项 九、Flet 文字倒影效果实现原理分析 (一)组件结构与功能 1. 图像…

2025最新深度学习面试必问100题--理论+框架+原理+实践 (下篇)

2025最新深度学习面试必问100题–理论框架原理实践 (下篇) 在上篇中&#xff0c;我们已经深入探讨了机器学习基础、CNN、RNN及其变体&#xff0c;以及模型优化的核心技巧。 在下篇中&#xff0c;我们将把目光投向更远方&#xff0c;聚焦于当今AI领域最炙手可热的前沿。我们将深…

原子工程用AC6编译不过问题

…\Output\atk_h750.axf: Error: L6636E: Pre-processor step failed for ‘…\User\SCRIPT\qspi_code.scf.scf’修改前&#xff1a; #! armcc -E ;#! armclang -E --targetarm-arm-none-eabi -mcpucortex-m7 -xc /* 使用说明 ! armclang -E --targetarm-arm-none-eabi -mcpuco…

Python有哪些经典的常用库?(第一期)

目录 1、NumPy (数值计算基础库) 核心特点&#xff1a; 应用场景&#xff1a; 代码示例&#xff1a; 2、Pandas (数据分析处理库) 应用场景&#xff1a; 代码示例&#xff1a; 3、Scikit-learn (机器学习库) 核心特点&#xff1a; 应用场景&#xff1a; 代码示例&am…

现代 C++ 高性能程序驱动器架构

&#x1f9e0; 现代 C 高性能程序驱动器架构M/PA&#xff08;多进程&#xff09;是隔离的“孤岛”&#xff0c;M/TA&#xff08;多线程&#xff09;是共享的“战场”&#xff0c;EDSM&#xff08;事件驱动&#xff09;是高效的“反应堆”&#xff0c;MDSM&#xff08;消息驱动&…