【每日一題】快照陣列

Aikoin發表於2024-05-03

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
  • 題目最多進行50000setsnap,和 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
        

相關文章