Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
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_idExample 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 <= 5 * 1040 <= index < length0 <= val <= 1090 <= snap_id < (the total number of times we call snap())5 * 104 calls will be made to set, snap, and get.Problem summary: 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
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Binary Search · Design
["SnapshotArray","set","snap","set","get"] [[3],[0,5],[],[0,6],[0,0]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1146: Snapshot Array
class SnapshotArray {
private List<int[]>[] arr;
private int idx;
public SnapshotArray(int length) {
arr = new List[length];
Arrays.setAll(arr, k -> new ArrayList<>());
}
public void set(int index, int val) {
arr[index].add(new int[] {idx, val});
}
public int snap() {
return idx++;
}
public int get(int index, int snap_id) {
int l = 0, r = arr[index].size();
while (l < r) {
int mid = (l + r) >> 1;
if (arr[index].get(mid)[0] > snap_id) {
r = mid;
} else {
l = mid + 1;
}
}
--l;
return l < 0 ? 0 : arr[index].get(l)[1];
}
}
/**
* Your SnapshotArray object will be instantiated and called as such:
* SnapshotArray obj = new SnapshotArray(length);
* obj.set(index,val);
* int param_2 = obj.snap();
* int param_3 = obj.get(index,snap_id);
*/
// Accepted solution for LeetCode #1146: Snapshot Array
type SnapshotArray struct {
arr [][][2]int
i int
}
func Constructor(length int) SnapshotArray {
return SnapshotArray{make([][][2]int, length), 0}
}
func (this *SnapshotArray) Set(index int, val int) {
this.arr[index] = append(this.arr[index], [2]int{this.i, val})
}
func (this *SnapshotArray) Snap() int {
this.i++
return this.i - 1
}
func (this *SnapshotArray) Get(index int, snap_id int) int {
i := sort.Search(len(this.arr[index]), func(i int) bool { return this.arr[index][i][0] > snap_id }) - 1
if i < 0 {
return 0
}
return this.arr[index][i][1]
}
/**
* Your SnapshotArray object will be instantiated and called as such:
* obj := Constructor(length);
* obj.Set(index,val);
* param_2 := obj.Snap();
* param_3 := obj.Get(index,snap_id);
*/
# Accepted solution for LeetCode #1146: Snapshot Array
class SnapshotArray:
def __init__(self, length: int):
self.arr = [[] for _ in range(length)]
self.i = 0
def set(self, index: int, val: int) -> None:
self.arr[index].append((self.i, val))
def snap(self) -> int:
self.i += 1
return self.i - 1
def get(self, index: int, snap_id: int) -> int:
i = bisect_left(self.arr[index], (snap_id, inf)) - 1
return 0 if i < 0 else self.arr[index][i][1]
# 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)
// Accepted solution for LeetCode #1146: Snapshot Array
type Pair = (usize, i32);
struct SnapshotArray {
size: usize,
data: Vec<Vec<Pair>>,
snap_id: usize,
}
impl SnapshotArray {
fn new(length: i32) -> Self {
let size = length as usize;
let data = vec![vec![(0, 0)]; size];
let snap_id = 0;
SnapshotArray {
size,
data,
snap_id,
}
}
fn set(&mut self, index: i32, val: i32) {
let i = index as usize;
if let Some(last) = self.data[i].pop() {
if last.0 != self.snap_id {
self.data[i].push(last);
}
}
self.data[i].push((self.snap_id, val));
}
fn snap(&mut self) -> i32 {
self.snap_id += 1;
(self.snap_id - 1) as i32
}
fn get(&self, index: i32, snap_id: i32) -> i32 {
let i = index as usize;
let snap_id = snap_id as usize;
match self.data[i].binary_search_by_key(&snap_id, |p| p.0) {
Ok(j) => self.data[i][j].1,
Err(j) => self.data[i][j - 1].1,
}
}
}
#[test]
fn test() {
let mut obj = SnapshotArray::new(3);
obj.set(0, 5);
assert_eq!(obj.snap(), 0);
obj.set(0, 6);
assert_eq!(obj.get(0, 0), 5);
}
// Accepted solution for LeetCode #1146: Snapshot Array
class SnapshotArray {
private arr: [number, number][][];
private i: number = 0;
constructor(length: number) {
this.arr = Array.from({ length }, () => []);
}
set(index: number, val: number): void {
this.arr[index].push([this.i, val]);
}
snap(): number {
return this.i++;
}
get(index: number, snap_id: number): number {
let [l, r] = [0, this.arr[index].length];
while (l < r) {
const mid = (l + r) >> 1;
if (this.arr[index][mid][0] > snap_id) {
r = mid;
} else {
l = mid + 1;
}
}
--l;
return l < 0 ? 0 : this.arr[index][l][1];
}
}
/**
* Your SnapshotArray object will be instantiated and called as such:
* var obj = new SnapshotArray(length)
* obj.set(index,val)
* var param_2 = obj.snap()
* var param_3 = obj.get(index,snap_id)
*/
Use this to step through a reusable interview workflow for this problem.
Check every element from left to right until we find the target or exhaust the array. Each comparison is O(1), and we may visit all n elements, giving O(n). No extra space needed.
Each comparison eliminates half the remaining search space. After k comparisons, the space is n/2ᵏ. We stop when the space is 1, so k = log₂ n. No extra memory needed — just two pointers (lo, hi).
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.