Every day a Leetcode
题目来源:1146. 快照数组
解法1:哈希 + 二分查找
每次调用 snap(),就复制一份数组的话,内存会爆。
为了节省内存,我们只存储修改的记录。调用 set(index,val) 时,不去修改数组,而是往 index 的历史修改记录末尾添加一条数据:此时的快照编号 cur_snap_id 和 val。
显然,历史修改记录中的快照编号是有序的。那我们在 get(int index, int snap_id) 时,就可以按 snap_id 做二分查找,找到编号小于等于 snap_id 的最新的修改记录,其中的 val 就是答案。
代码:
/*
* @lc app=leetcode.cn id=1146 lang=cpp
*
* [1146] 快照数组
*/
// @lc code=start
class SnapshotArray
{
private:
// 当前 snap_id
int cur_snap_id = 0;
// 每个 index 的历史修改记录
unordered_map<int, vector<pair<int, int>>> history;
public:
SnapshotArray(int length)
{
}
void set(int index, int val)
{
auto p = pair<int, int>(cur_snap_id, val);
history[index].push_back(p);
}
int snap()
{
return cur_snap_id++;
}
int get(int index, int snap_id)
{
auto &h = history[index];
// 找快照编号 <= snap_id 的最后一次修改记录
// 等价于找快照编号 >= snap_id+1 的第一个修改记录,它的上一个就是答案
pair<int, int> p = {snap_id + 1, -1};
int j = lower_bound(h.begin(), h.end(), p) - h.begin() - 1;
return j >= 0 ? h[j].second : 0;
}
};
/**
* Your SnapshotArray object will be instantiated and called as such:
* SnapshotArray* obj = new SnapshotArray(length);
* obj->set(index,val);
* int param_2 = obj->snap();
* int param_3 = obj->get(index,snap_id);
*/
// @lc code=end
结果:
复杂度分析:
时间复杂度:初始化、set、snap 均为 O(1),get 为 O(logq),其中 q 为 set 的调用次数。
空间复杂度:O(q),其中 q 为 set 的调用次数。