Implement a SnapshotArray that supports the following interface:
SnapshotArray(int length) initializes an array-like data structure with the given length. Initially, each element equals 0.
void set(index, val) sets the element at the given index to be equal to val.
int snap() takes a snapshot of the array and returns the snap_id: the total number of times we called snap() minus 1.
int get(index, snap_id) returns the value at the given index, at the time we took the snapshot with the given snap_id
Example 1:
Input: [“SnapshotArray”,“set”,“snap”,“set”,“get”]
[[3],[0,5],[],[0,6],[0,0]]
Output: [null,null,0,null,5]
Explanation:
SnapshotArray snapshotArr = new SnapshotArray(3); // set the length to be 3
snapshotArr.set(0,5); // Set array[0] = 5
snapshotArr.snap(); // Take a snapshot, return snap_id = 0
snapshotArr.set(0,6);
snapshotArr.get(0,0); // Get the value of array[0] with snap_id = 0, return 5
Constraints:
- 1 <= length <= 50000
- At most 50000 calls will be made to set, snap, and get.
- 0 <= index < length
- 0 <= snap_id < (the total number of times we call snap())
- 0 <= val <= 10^9
思路很简单, 看到条件中的 length <= 50000, 我们首先应该排除真的给整个数组做快照, 否则超时是妥妥的了, 我们在数组里保存每个值的历史状态,但是这里要考虑一个前提条件,就是如果在设置之前拍过快照,那我们就需要新建一个历史状态, 否则的话我们只需要修改最后一个历史状态即可。然后获取的时候我们只需要二分查找每个值的历史记录即可。这里要注意一点,我们在 SnapshotArray 中维护一个下一个快照的 id, 每次 snap 之后,该 id+1, 在获取的时候, 只有历史状态里的 snap_idx 小于该值才是拍过快照的历史, 因为最后一个历史状态有可能是没有拍过快照的。
捎带说一句, 这题如果用 HashMap 来保存历史使用的内存可能会更小, 但是如果不做初始化, 判断情况会复杂很多, 在无数次试错后我放弃了, 感兴趣的同学可以试试
struct SnapshotArray {
s: i32,
l: Vec<Vec<(i32, i32)>>,
}
impl SnapshotArray {
fn new(length: i32) -> Self {
Self {
s: 0,
l: vec![vec![(0, 0)]; length as usize],
}
}
fn set(&mut self, index: i32, val: i32) {
if self.s > self.l[index as usize].last().unwrap().0 {
self.l[index as usize].push((self.s, val));
return;
}
self.l[index as usize].last_mut().unwrap().1 = val;
}
fn snap(&mut self) -> i32 {
self.s += 1;
self.s - 1
}
fn get(&self, index: i32, snap_id: i32) -> i32 {
let history = &self.l[index as usize];
let mut l = 0;
let mut h = history.len() - 1;
while l < h {
let m = (l + h) / 2;
if history[m].0 == snap_id {
return history[m].1;
} else if history[m].0 < snap_id {
l = m + 1;
} else {
h = m;
}
}
if history[l].0 == self.s || history[l].0 > snap_id {
return history[l - 1].1;
}
return history[l].1;
}
}