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.
Alice frequently takes exams and wants to track her scores and calculate the total scores over specific time periods.
Implement the ExamTracker class:
ExamTracker(): Initializes the ExamTracker object.void record(int time, int score): Alice takes a new exam at time time and achieves the score score.long long totalScore(int startTime, int endTime): Returns an integer that represents the total score of all exams taken by Alice between startTime and endTime (inclusive). If there are no recorded exams taken by Alice within the specified time interval, return 0.It is guaranteed that the function calls are made in chronological order. That is,
record() will be made with strictly increasing time.record() is called with time = t, then totalScore() will always be called with startTime <= endTime <= t.Example 1:
Input:
["ExamTracker", "record", "totalScore", "record", "totalScore", "totalScore", "totalScore", "totalScore"]
[[], [1, 98], [1, 1], [5, 99], [1, 3], [1, 5], [3, 4], [2, 5]]
Output:
[null, null, 98, null, 98, 197, 0, 99]
Explanation
ExamTracker examTracker = new ExamTracker();98 + 99 = 197.Constraints:
1 <= time <= 1091 <= score <= 1091 <= startTime <= endTime <= t, where t is the value of time from the most recent call of record().record() will be made with strictly increasing time.ExamTracker(), the first function call will always be record().105 calls will be made in total to record() and totalScore().Problem summary: Alice frequently takes exams and wants to track her scores and calculate the total scores over specific time periods. Implement the ExamTracker class: ExamTracker(): Initializes the ExamTracker object. void record(int time, int score): Alice takes a new exam at time time and achieves the score score. long long totalScore(int startTime, int endTime): Returns an integer that represents the total score of all exams taken by Alice between startTime and endTime (inclusive). If there are no recorded exams taken by Alice within the specified time interval, return 0. It is guaranteed that the function calls are made in chronological order. That is, Calls to record() will be made with strictly increasing time. Alice will never ask for total scores that require information from the future. That is, if the latest record() is called with time = t, then totalScore() will always be called with
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Binary Search · Design
["ExamTracker","record","totalScore","record","totalScore","totalScore","totalScore","totalScore"] [[],[1,98],[1,1],[5,99],[1,3],[1,5],[3,4],[2,5]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3709: Design Exam Scores Tracker
class ExamTracker {
private List<Integer> times = new ArrayList<>();
private List<Long> pre = new ArrayList<>();
public ExamTracker() {
times.add(0);
pre.add(0L);
}
public void record(int time, int score) {
times.add(time);
pre.add(pre.getLast() + score);
}
public long totalScore(int startTime, int endTime) {
int l = binarySearch(startTime) - 1;
int r = binarySearch(endTime + 1) - 1;
return pre.get(r) - pre.get(l);
}
private int binarySearch(int x) {
int l = 0, r = times.size();
while (l < r) {
int mid = (l + r) >> 1;
if (times.get(mid) >= x) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
}
/**
* Your ExamTracker object will be instantiated and called as such:
* ExamTracker obj = new ExamTracker();
* obj.record(time,score);
* long param_2 = obj.totalScore(startTime,endTime);
*/
// Accepted solution for LeetCode #3709: Design Exam Scores Tracker
type ExamTracker struct {
times []int
pre []int64
}
func Constructor() ExamTracker {
return ExamTracker{[]int{0}, []int64{int64(0)}}
}
func (this *ExamTracker) Record(time int, score int) {
this.times = append(this.times, time)
this.pre = append(this.pre, this.pre[len(this.pre)-1]+int64(score))
}
func (this *ExamTracker) TotalScore(startTime int, endTime int) int64 {
l := sort.SearchInts(this.times, startTime) - 1
r := sort.SearchInts(this.times, endTime+1) - 1
return this.pre[r] - this.pre[l]
}
/**
* Your ExamTracker object will be instantiated and called as such:
* obj := Constructor();
* obj.Record(time,score);
* param_2 := obj.TotalScore(startTime,endTime);
*/
# Accepted solution for LeetCode #3709: Design Exam Scores Tracker
class ExamTracker:
def __init__(self):
self.times = [0]
self.pre = [0]
def record(self, time: int, score: int) -> None:
self.times.append(time)
self.pre.append(self.pre[-1] + score)
def totalScore(self, startTime: int, endTime: int) -> int:
l = bisect_left(self.times, startTime) - 1
r = bisect_left(self.times, endTime + 1) - 1
return self.pre[r] - self.pre[l]
# Your ExamTracker object will be instantiated and called as such:
# obj = ExamTracker()
# obj.record(time,score)
# param_2 = obj.totalScore(startTime,endTime)
// Accepted solution for LeetCode #3709: Design Exam Scores Tracker
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #3709: Design Exam Scores Tracker
// class ExamTracker {
// private List<Integer> times = new ArrayList<>();
// private List<Long> pre = new ArrayList<>();
//
// public ExamTracker() {
// times.add(0);
// pre.add(0L);
// }
//
// public void record(int time, int score) {
// times.add(time);
// pre.add(pre.getLast() + score);
// }
//
// public long totalScore(int startTime, int endTime) {
// int l = binarySearch(startTime) - 1;
// int r = binarySearch(endTime + 1) - 1;
// return pre.get(r) - pre.get(l);
// }
//
// private int binarySearch(int x) {
// int l = 0, r = times.size();
// while (l < r) {
// int mid = (l + r) >> 1;
// if (times.get(mid) >= x) {
// r = mid;
// } else {
// l = mid + 1;
// }
// }
// return l;
// }
// }
//
// /**
// * Your ExamTracker object will be instantiated and called as such:
// * ExamTracker obj = new ExamTracker();
// * obj.record(time,score);
// * long param_2 = obj.totalScore(startTime,endTime);
// */
// Accepted solution for LeetCode #3709: Design Exam Scores Tracker
class ExamTracker {
private times: number[] = [0];
private pre: number[] = [0];
constructor() {}
record(time: number, score: number): void {
this.times.push(time);
this.pre.push(this.pre.at(-1)! + score);
}
totalScore(startTime: number, endTime: number): number {
const l = _.sortedIndex(this.times, startTime) - 1;
const r = _.sortedIndex(this.times, endTime + 1) - 1;
return this.pre[r] - this.pre[l];
}
}
/**
* Your ExamTracker object will be instantiated and called as such:
* var obj = new ExamTracker()
* obj.record(time,score)
* var param_2 = obj.totalScore(startTime,endTime)
*/
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: 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.