力扣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 的值。

二.题目分析

(1)上岸第一步:理清思路

        实现一个快照数组,满足四个接口函数,通过题意分析可知,每次set操作后都会形成一个新的数组并覆盖原数组,即会多一个历史版本;而snap函数则是需要返回历史版本的个数(从0开始计数);get(int index,int snap_id)函数则要返回第snap_id个历史版本的第index个元素的值

        因此,我们的历史版本数组必须保存下来,其保存方法有很多考究,是每次都赋值一个新的数组呢还是有其他新的方法呢?如果次次复制新的数组,无疑内存会爆掉的,因此我们需要一个简单且占用内存较小的方式来保留历史数据。

        我采用的是开一个vector数组将元素序号、历史版本、元素值结合起来存储的方法,vector数组中每个元素也是一个vector数组,里面存储的是对应历史版本和对应元素数值(干说可能有点难以解,别担心,我们用例子模演一遍,友友们就可以更好地理解了,如下)

(2)上岸第二步:分模块实践代码

 我们需要一个data数组来存储其历史数据和一个计数器来记录历史版本个数:

vector<vector<pair<int,int>>> data;//历史版本数据存储数组
int snap_cnt;//存储历史版本个数

.SnapshotArray():初始化元素全为0

SnapshotArray(int length):snap_cnt(0),data(length){}
//构造函数,初始化成员变量snap_cnt的值和data数组的长度

void set(index,val):将第index个元素设置为val,并开始记录历史版本数据

void set(int index,int val)
{
   data[index].emplace_back(snap_cnt, val);
//emplace函数在向量末尾直接构造一个符合数据类型的元素,避免额外复制和移动操作
}

int snap():获取快照次数,即历史版本个数

int snap()
{
   return snap_cnt;
}

int get(int index,int snap_id):返回第snap_id个历史版本的第index个元素的值

int get(int index,int snap_id)
{
   auto x=upper_bound(data[index].begin(),data[index].end(),pair{snap_id+1,-1});
 //得到第index个元素的所有取值中第一个大于{snap_id+1,-1}的元素的位置,并赋值给x
   return x == data[index].begin() ? 0 : prev(x)->second;
//x是否为这个元素桶的起始数值,是则返回0,如果不是,则返回x得到的数组对的第二个值,即要返回的第index个元素的第snap_id版本的数值
}

(3)上岸第三步:整合思路,上完整代码

class SnapshotArray {
public:
    SnapshotArray(int length): snap_cnt(0), data(length) {}
    //初始化快照数组,其元素为0
    
    void set(int index, int val) {
        data[index].emplace_back(snap_cnt, val);
    }//将指定索引的元素值设置为val
    
    int snap() {
        return snap_cnt++;
    }
    
    int get(int index, int snap_id) {
        auto x = upper_bound(data[index].begin(), data[index].end(), pair{snap_id + 1, -1});
        return x == data[index].begin() ? 0 : prev(x)->second;
    }

private:
    int snap_cnt;
    vector<vector<pair<int, int>>> data;
};

(4)上岸最后一步:反思+总结

个人认为这道题还挺难的,最迷惑人的点其实是题目意思解读,题目理解对真的非常重要!!!理解了题目意思,思维逻辑和代码实现并不是很难,主要优化内存和运行速度用到了二分和vector数组的相关应用,也不难,直接调库就行,简而言之,友友们一定要理解对题目意思,一起噶油呀

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值