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

LeetCode 2080 区间频率查询详解(哈希表 + 二分法)

深度解析:空间换时间的艺术 —— 从区间频率查询看哈希与二分

在处理大规模数据查询时,性能优化是核心。LeetCode 2080 题《区间内查询数字的频率》是一个绝佳的案例。本文将通过“哈希表预处理”与“二分查找”两大维度,带你领略现代 C++ 的解题美学。

一、 哈希表:构建高效的“档案库”

在本题中,如果我们每次查询都遍历区间,时间复杂度是 O(N),面对 10^5 级别的查询必然超时。我们的策略是构建一个 unordered_map<int, vector>。

1. 结构深度解析

这个结构可以理解为一个“分类索引”:

  • Key (键):数组中出现的具体数值(如 33)。
  • Value (值):一个升序排列的 vector,记录了该数值在原数组中出现的所有下标(如 [1, 3, 5])。

2. 增删改查的实战用法

在 C++ 中,unordered_map 是基于哈希表实现的,其平均操作效率为 O(1):

  • 增/改:

    pos[val].push_back(index); // 若 val 不存在,会自动创建一个空的 vector 并添加 index
  • 查(标准定式):
    为了避免不必要的插入(副作用),推荐使用 find() 配合 end() 进行检查:

    auto it = pos.find(target); if (it != pos.end()) { // 找到了,it->second 就是我们要的下标 vector }
  • 删:

pos.erase(val); // 即可瞬间根据键删除对应的内容。

3. 性能关键

在查询函数中,你会看到这样的代码:

auto& a = it->second;
  • 为什么要加 &?
  • 如果不加 &,程序会把整个 vector 拷贝一遍。加上 & 后,a 仅仅是原哈希表中 vector 的一个别名,没有任何数据复制。在处理海量数据时,这一个字符之差就是 TLE(超时)与 AC(通过)的分水岭。

二、 二分查找

有了有序的下标数组后,核心任务就是:在有序数组中,统计有多少个下标落在 [left, right] 之间。此时,std::lower_bound 和 std::upper_bound 就派上用场了。

1. lower_bound:定位左边界

  • 功能:在有序序列中找到第一个 大于等于 (>=) 给定值的元素位置。
  • 应用:lower_bound(a, left) 帮我们找到第一个落在区间内的有效下标位置。

2. upper_bound:定位右边界

  • 功能:在有序序列中找到第一个 严格大于 (>) 给定值的元素位置。
  • 应用:upper_bound(a, right) 帮我们找到第一个“越出”右边界的位置。

3. 核心计算公式

两个迭代器相减,即是该数值在区间内出现的次数:

return ranges::upper_bound(a, right) - ranges::lower_bound(a, left);

三、 完整实现代码 (C++20 风格)

class RangeFreqQuery { // 哈希表:数值 -> 有序下标数组 unordered_map<int, vector<int>> pos; public: RangeFreqQuery(vector<int>& arr) { // 预处理:O(N) 建立索引 for (int i = 0; i < arr.size(); ++i) { pos[arr[i]].push_back(i); // 顺序遍历确保了下标序列是天然升序的 } } int query(int left, int right, int value) { // 使用定式查找,避免副作用 auto it = pos.find(value); if (it == pos.end()) return 0; // 数值根本没出现过 // 获取引用 (&),拒绝大规模拷贝 const auto& a = it->second; // 二分查找:O(log M) auto L = std::ranges::lower_bound(a, left); auto R = std::ranges::upper_bound(a, right); return R - L; // 迭代器相减得到元素个数 } };

四、 总结

本题是典型的“空间换时间”策略。我们通过哈希表将乱序数组按值分类,再通过二分法将线性搜索优化为对数搜索。

关键点回顾:

  1. 哈希表:掌握 find 定式,通过 Key 瞬间定位数据。
  2. 引用 &:它是 C++ 程序员的性能尊严,拒绝无谓拷贝。
  3. 二分边界:记住 lower 是第一个“不小于”,upper 是第一个“大于”。

相关链接:https://github.com/0voice

http://www.jsqmd.com/news/216978/

相关文章:

  • 彻底搞懂浏览器原生录制:MediaRecorder API 深度解析
  • AI大模型架构师必学指南:从知识储备到高薪前景,一篇收藏就够了!
  • IoT 场景中的 DHCP、ARP、ICMP 到底在干嘛?
  • MySql-9.1.0安装详细教程(保姆级)
  • AI产品经理转型与大模型学习路线图,附赠全套学习资源_月薪3W的AI产品经理学习路线
  • 大模型学习宝典:从小白到专家的进阶之路,建议收藏反复阅读
  • 【ITK手册006】itk::Point 深度解析与实用指南
  • 主流AI平台用户占55%,SHEEP-GEO凭五维模型成企业AI搜索战略伙伴
  • MySQL 时区参数 time_zone 详解
  • 量化交易脚本开发:DeepSeek生成技术指标计算与信号触发代码
  • MySQL 数据增删改查
  • RAG Agent记忆功能完全指南:3种方法解决长对话上下文丢失问题
  • Ehercat代码解析中文摘录<8>
  • 太流批了,老牌软件,数据对比神器
  • 个性化旅游行程规划系统-计算机毕业设计源码+LW文档
  • 收藏!裸辞转型AI大模型,我的完整攻略与经验分享
  • 北大团队创新方案:CKDA框架解决跨模态行人重识别的持续学习痛点
  • 2026年--Lc333-328. 奇偶链表(链表)--java版
  • AI会取代前端吗?2026年前端发展路线图,建议收藏学习
  • MySQL 数据库连接数查询、配置
  • 牛批了,桌牌台签神器,批量制作
  • MySQL5.7.44-winx64版本Windows Server下载安装教程图解
  • AI Agent记忆系统大揭秘:从“失忆“到“长记性“的进化之路(附代码实战)
  • MySQL 数据库基础
  • 基于python大数据的协同过滤音乐推荐系统
  • K8S网络和基本命令 【 K8S (二)】
  • MySQL 的 INSERT(插入数据)详解
  • MySQL 篇 - Java 连接 MySQL 数据库并实现数据交互
  • 基于BS架构的积分制零食自选平台-计算机毕业设计源码+LW文档
  • MySQL 查看有哪些表