news 2026/9/2 22:39:14

二分查找(十)1146. 快照数组 pair整理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
二分查找(十)1146. 快照数组 pair整理

1146. 快照数组

实现支持下列接口的「快照数组」- SnapshotArray:

  • SnapshotArray(int length)- 初始化一个与指定长度相等的 类数组 的数据结构。初始时,每个元素都等于0
  • void set(index, val)- 会将指定索引index处的元素设置为val
  • int snap()- 获取该数组的快照,并返回快照的编号snap_id(快照号是调用snap()的总次数减去1)。
  • int get(index, snap_id)- 根据指定的snap_id选择快照,并返回该快照指定索引index的值。

示例:

输入:["SnapshotArray","set","snap","set","get"] [[3],[0,5],[],[0,6],[0,0]]输出:[null,null,0,null,5]解释:SnapshotArray snapshotArr = new SnapshotArray(3); // 初始化一个长度为 3 的快照数组 snapshotArr.set(0,5); // 令 array[0] = 5 snapshotArr.snap(); // 获取快照,返回 snap_id = 0 snapshotArr.set(0,6); snapshotArr.get(0,0); // 获取 snap_id = 0 的快照中 array[0] 的值,返回 5

解法一:使用map存储数组的情况虽然方便理解,但是遇到大量请求的时候,导致大量的深拷贝操作进行,超时。

class SnapshotArray { public: SnapshotArray(int length) { ShotArray.resize(length, 0); } void set(int index, int val) { ShotArray[index] = val; } int snap() { ShotArrays[snap_id++] = ShotArray; return snap_id-1; } int get(int index, int snap_id) { return ShotArrays[snap_id][index]; } private: map<int, vector<int>> ShotArrays; vector<int> ShotArray; int snap_id = 0; };

思路
假设每调用一次 set,就生成一个快照(复制一份数组)。仅仅是一个元素发生变化,就去复制整个数组,这太浪费了。

能否不复制数组呢?

换个视角,调用 set(index,val) 时,不去修改数组,而是往 index 的历史修改记录末尾添加一条数据:此时的快照编号和 val。

举例说明:

在快照编号等于 2 时,调用 set(0,6)。
在快照编号等于 3 时,调用 set(0,1)。
在快照编号等于 3 时,调用 set(0,7)。
在快照编号等于 5 时,调用 set(0,2)。
这四次调用结束后,下标 0 的历史修改记录 history[0]=[(2,6),(3,1),(3,7),(5,2)],每个数对中的第一个数为调用 set 时的快照编号,第二个数为调用 set 时传入的 val。注意历史修改记录中的快照编号是有序的。
那么:

调用 get(0,4)。由于历史修改记录中的快照编号是有序的,我们可以在 history[0] 中二分查找快照编号 ≤4 的最后一条修改记录,即 (3,7)。修改记录中的 val=7 就是答案。
调用 get(0,1)。在 history[0] 中,快照编号 ≤1 的记录不存在,说明在快照编号 ≤1 时,我们没有修改下标 0 保存的元素,返回初始值 0。

class SnapshotArray { // 建议:history 改名为 records 可能更直观 unordered_map<int, vector<pair<int,int>>> history; int snap_id = 0; public: SnapshotArray(int length) { // map 不需要预分配空间,这里空着也没事 } void set(int index, int val) { // 【修正1】加上引用 &,或者直接操作 map // 这样才能真正修改 map 里的数据 history[index].push_back({snap_id, val}); } int snap() { snap_id++; return snap_id - 1; } int get(int index, int snap_id) { // 【注意】这里不要用 auto it = history[index],因为会产生巨大的拷贝开销! // 如果只是读取,最好用引用,或者直接用 history.find(index) // 如果这个 index 从来没存过数据,直接返回 0 if (history.find(index) == history.end()) { return 0; } auto& vec = history[index]; // 加上引用 & 避免拷贝!! // 二分查找 auto it = upper_bound(vec.begin(), vec.end(), make_pair(snap_id, 2000000000)); // 【修正2】判断边界 // 如果它是 begin(),说明所有记录的 snap_id 都比查询的 snap_id 大(或者数组为空) // 这种情况下应该返回初始值 0 if (it == vec.begin()) { return 0; } // 安全地回退一步 return prev(it)->second; } };

使用auto拿一个对象里面数据的时候,不管要不要进行修改,都尽量加上引用;

lower_bound找不到返回end() upper_bound找不到返回begin()

#include <iostream> #include <utility> #include <vector> #include <algorithm> using namespace std; int main() { // 1. 增 pair<int, int> p = {5, 10}; // 2. 改 p.first = 99; // 3. 查 (C++17 酷炫写法) auto [x, y] = p; cout << "x: " << x << ", y: " << y << endl; // x: 99, y: 10 // 4. 排序演示 vector<pair<int, int>> vec = {{2, 10}, {1, 20}, {1, 5}}; sort(vec.begin(), vec.end()); // 排序后顺序:{1, 5}, {1, 20}, {2, 10} for(auto& item : vec) { cout << "{" << item.first << "," << item.second << "} "; } return 0; }

lambda自定义排序

sort(vec.begin(), vec.end(), [](const auto& a, const auto& b) { // 逻辑:return true 代表 a 应该排在 b 前面 // 情况1:主关键字不同,按主关键字排(比如按 value 降序) if (a.second != b.second) { return a.second > b.second; } // 情况2:主关键字相同,按次关键字排(比如按 key 升序) return a.first < b.first; });
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 21:35:30

亲测5款热门台球手游,休闲局竟能玩出竞技感

最近线下台球馆的火爆程度持续攀升&#xff0c;从街头巷尾的小店到高端俱乐部&#xff0c;随处可见握杆击球的身影。但场地受限、时间冲突、消费成本等问题&#xff0c;让不少爱好者难以随时享受台球乐趣。为此&#xff0c;笔者亲测了北京喜云网络科技有限公司旗下天天台球、腾…

作者头像 李华
网站建设 2026/9/2 21:30:10

2核2G3M服务器中的3M指的是上行还是下行带宽?速度是多少?

很多人买阿里云 ECS 时&#xff0c;看到“2核2G3M”就以为带宽是“上下行各3M”。 结果网站加载慢&#xff0c;文件下载卡&#xff0c;还以为是服务器性能问题。 其实&#xff0c;这“3M”只指上行带宽——也就是服务器往外传数据的速度。 如阿里云的2核2G3M服务器&#xff…

作者头像 李华
网站建设 2026/9/2 20:40:34

基层防灾工程便携式气象仪

Q1&#xff1a;这款便携气象仪的核心定位是什么&#xff1f;为何适配应急救援与基层防灾场景&#xff1f;A&#xff1a;核心定位是“基层防灾工程与应急救援专用移动式气象监测终端”&#xff0c;专注解决现场气象监测“搭建慢、便携差、数据缺、传输缓”的痛点&#xff0c;聚焦…

作者头像 李华
网站建设 2026/8/31 15:25:35

草原生态气象站 草原气象环境监测系统

Q1&#xff1a;草原生态气象站的核心定位是什么&#xff1f;为何适配草原场景需求&#xff1f; A&#xff1a;核心定位是“草原生态监测与牧区生产保障专用气象设备”&#xff0c;专注解决草原场景“气象要素监测不全、设备抗逆性弱、长期运行难、灾害预警滞后”的痛点&#xf…

作者头像 李华
网站建设 2026/9/2 11:52:17

miniforge

既然你已经彻底卸载了 Anaconda&#xff0c;现在的系统非常清爽&#xff0c;正是安装 Miniforge 的最佳时机。 Miniforge 的安装和使用逻辑与 Anaconda 极其相似&#xff0c;但它更轻、更快、且完全免费。 以下是保姆级的安装与使用指南&#xff1a; 一、 安装 Miniforge (In…

作者头像 李华
网站建设 2026/8/27 6:42:51

学霸同款10个一键生成论文工具,本科生搞定毕业论文!

学霸同款10个一键生成论文工具&#xff0c;本科生搞定毕业论文&#xff01; AI 工具如何让论文写作不再难 对于本科生来说&#xff0c;撰写毕业论文是一项既重要又复杂的任务。从选题到开题&#xff0c;再到资料收集、撰写和降重&#xff0c;每一个环节都可能成为压力源。而如今…

作者头像 李华