题目:
实现支持下列接口的「快照数组」- 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的值。

思考:
暴力解法
用一个长度为length的数组记录当前的数组值,用一个字典记录每一次快照时的数组和快照编号,代码如下:
class SnapshotArray(object):
    def __init__(self, length):
        """
        :type length: int
        """
        self.array = [0 for _ in range(length)]
        self.snapshot = {}
        self.snap_time = -1
    def set(self, index, val):
        """
        :type index: int 
        :type val: int
        :rtype: None
        """
        self.array[index] = val
    def snap(self):
        """
        :rtype: int
        """
        self.snap_time += 1
        self.snapshot[self.snap_time] = list(self.array)    # 使用 list() 确保存储的是数组的副本
        return self.snap_time
    def get(self, index, snap_id):
        """
        :type index: int
        :type snap_id: int
        :rtype: int
        """
        return self.snapshot[snap_id][index]
# Your SnapshotArray object will be instantiated and called as such:
# obj = SnapshotArray(length)
# obj.set(index,val)
# param_2 = obj.snap()
# param_3 = obj.get(index,snap_id)提交卡在第 69 / 75 个例子,超内存了:

优化(参考灵神的题解)
不需要每次快照的时候都把数组复制下来,由于get()函数是通过给定的 snap_id 和 index 得到对应值,那我们就用一个数据结构(命名为history)记录所有(改变过值的)数组元素每次改变时的快照次数snap_time和改变后的值val,即(snap_time, val)。
这样,调用get()函数即:找到index对应的数组元素的history,在history中找到满足snap_time < snap_id条件的最后一个(snap_time, val)对,val即为所求。
问题一、history用什么数据结构?
整体用字典存储,键是每个元素的index,值是每个元素的history(用列表存储(snap_time, val)对)。
问题二、怎么在history中找到满足snap_time ≤ snap_id条件的最后一个(snap_time, val)对
因为history中的(snap_time, val)对是按照snap_time从小到大排列的,所以可以用二分查找提高效率。
代码如下:
class SnapshotArray(object):
    def __init__(self, length):
        """
        :type length: int
        """
        self.history = defaultdict(list)
        self.cur_snap = -1
    def set(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        # 记录(snap_time, val)对
        self.history[index].append([self.cur_snap, val])
    def snap(self):
        """
        :rtype: int
        """
        self.cur_snap += 1
        return self.cur_snap
    def get(self, index, snap_id):
        """
        :type index: int
        :type snap_id: int
        :rtype: int
        """
        # 在index对应元素的history中找到满足snap_time < snap_id条件的最后一个(snap_time, val)对,val即为所求
        # 如果元素没有修改过,直接返回0
        L = self.history[index]
        if not L:
            return 0
        # 二分查找
        left = 0
        right = len(L) - 1
        ans = 0
        
        while left <= right:
            mid = (left + right) // 2
            if L[mid][0] < snap_id:
                ans = L[mid][1]
                left = mid + 1
            else:
                right = mid - 1
        return ans
# Your SnapshotArray object will be instantiated and called as such:
# obj = SnapshotArray(length)
# obj.set(index,val)
# param_2 = obj.snap()
# param_3 = obj.get(index,snap_id)提交通过:











