题目:
实现支持下列接口的「快照数组」- 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)
提交通过: