题目:
实现支持下列接口的「快照数组」- 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 = -1def set(self, index, val):""":type index: int :type val: int:rtype: None"""self.array[index] = valdef snap(self):""":rtype: int"""self.snap_time += 1self.snapshot[self.snap_time] = list(self.array) # 使用 list() 确保存储的是数组的副本return self.snap_timedef 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 = -1def 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 += 1return self.cur_snapdef get(self, index, snap_id):""":type index: int:type snap_id: int:rtype: int"""# 在index对应元素的history中找到满足snap_time < snap_id条件的最后一个(snap_time, val)对,val即为所求# 如果元素没有修改过,直接返回0L = self.history[index]if not L:return 0# 二分查找left = 0right = len(L) - 1ans = 0while left <= right:mid = (left + right) // 2if L[mid][0] < snap_id:ans = L[mid][1]left = mid + 1else:right = mid - 1return 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)
提交通过: