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
的值。
示例:
輸入:["SnapshotArray","set","snap","set","get"]
[[3],[0,5],[],[0,6],[0,0]]
輸出:[null,null,0,null,5]
解釋:
SnapshotArray snapshotArr = new SnapshotArray(3); // 初始化一個長度為 3 的快照陣列
snapshotArr.set(0,5); // 令 array[0] = 5
snapshotArr.snap(); // 獲取快照,返回 snap_id = 0
snapshotArr.set(0,6);
snapshotArr.get(0,0); // 獲取 snap_id = 0 的快照中 array[0] 的值,返回 5
提示:
1 <= length <= 50000
- 題目最多進行
50000
次set
,snap
,和get
的呼叫 。 0 <= index < length
0 <= snap_id <
我們呼叫snap()
的總次數0 <= val <= 10^9
今天這題看似不難,我分了兩天寫完的。。一開始簡單粗暴法記憶體超了,又死活不想用二分,搞了各種花樣還是有問題,後面乾脆二分法結束。。
思路就是對陣列中的每個位置i
維護一個列表 data[i]
,其中儲存了若干二元組,按照時間順序記錄了每一次對位置i
的修改操作。
每次set操作,把當前的快照編號和修改的值作為二元組存在索引對應的列表裡,最後get的時候就查詢最後一個編號小於等於查詢快照號的值。
class SnapshotArray:
def __init__(self, length: int):
self.snap_cnt = 0
self.data = defaultdict(list) # 每個index的歷史修改記錄
def set(self, index: int, val: int) -> None:
self.data[index].append((self.snap_cnt, val))
def snap(self) -> int:
self.snap_cnt += 1
return self.snap_cnt - 1
def get(self, index: int, snap_id: int) -> int:
# 找到snap_cnt <= snap_id 的最後一條修改記錄
# 等價找到snap_cnt >= snap_id+1 的第一條修改記錄的前一條
i = bisect_left(self.data[index], (snap_id+1,)) - 1
return self.data[index][i][1] if i >=0 else 0