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.
You are given two integer arrays persons and times. In an election, the ith vote was cast for persons[i] at time times[i].
For each query at a time t, find the person that was leading the election at time t. Votes cast at time t will count towards our query. In the case of a tie, the most recent vote (among tied candidates) wins.
Implement the TopVotedCandidate class:
TopVotedCandidate(int[] persons, int[] times) Initializes the object with the persons and times arrays.int q(int t) Returns the number of the person that was leading the election at time t according to the mentioned rules.Example 1:
Input ["TopVotedCandidate", "q", "q", "q", "q", "q", "q"] [[[0, 1, 1, 0, 0, 1, 0], [0, 5, 10, 15, 20, 25, 30]], [3], [12], [25], [15], [24], [8]] Output [null, 0, 1, 1, 0, 0, 1] Explanation TopVotedCandidate topVotedCandidate = new TopVotedCandidate([0, 1, 1, 0, 0, 1, 0], [0, 5, 10, 15, 20, 25, 30]); topVotedCandidate.q(3); // return 0, At time 3, the votes are [0], and 0 is leading. topVotedCandidate.q(12); // return 1, At time 12, the votes are [0,1,1], and 1 is leading. topVotedCandidate.q(25); // return 1, At time 25, the votes are [0,1,1,0,0,1], and 1 is leading (as ties go to the most recent vote.) topVotedCandidate.q(15); // return 0 topVotedCandidate.q(24); // return 0 topVotedCandidate.q(8); // return 1
Constraints:
1 <= persons.length <= 5000times.length == persons.length0 <= persons[i] < persons.length0 <= times[i] <= 109times is sorted in a strictly increasing order.times[0] <= t <= 109104 calls will be made to q.Problem summary: You are given two integer arrays persons and times. In an election, the ith vote was cast for persons[i] at time times[i]. For each query at a time t, find the person that was leading the election at time t. Votes cast at time t will count towards our query. In the case of a tie, the most recent vote (among tied candidates) wins. Implement the TopVotedCandidate class: TopVotedCandidate(int[] persons, int[] times) Initializes the object with the persons and times arrays. int q(int t) Returns the number of the person that was leading the election at time t according to the mentioned rules.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Binary Search · Design
["TopVotedCandidate","q","q","q","q","q","q"] [[[0,1,1,0,0,1,0],[0,5,10,15,20,25,30]],[3],[12],[25],[15],[24],[8]]
rank-teams-by-votes)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #911: Online Election
class TopVotedCandidate {
private int[] times;
private int[] wins;
public TopVotedCandidate(int[] persons, int[] times) {
int n = persons.length;
wins = new int[n];
this.times = times;
int[] cnt = new int[n];
int cur = 0;
for (int i = 0; i < n; ++i) {
int p = persons[i];
++cnt[p];
if (cnt[cur] <= cnt[p]) {
cur = p;
}
wins[i] = cur;
}
}
public int q(int t) {
int i = Arrays.binarySearch(times, t + 1);
i = i < 0 ? -i - 2 : i - 1;
return wins[i];
}
}
/**
* Your TopVotedCandidate object will be instantiated and called as such:
* TopVotedCandidate obj = new TopVotedCandidate(persons, times);
* int param_1 = obj.q(t);
*/
// Accepted solution for LeetCode #911: Online Election
type TopVotedCandidate struct {
times []int
wins []int
}
func Constructor(persons []int, times []int) TopVotedCandidate {
n := len(persons)
wins := make([]int, n)
cnt := make([]int, n)
cur := 0
for i, p := range persons {
cnt[p]++
if cnt[cur] <= cnt[p] {
cur = p
}
wins[i] = cur
}
return TopVotedCandidate{times, wins}
}
func (this *TopVotedCandidate) Q(t int) int {
i := sort.SearchInts(this.times, t+1) - 1
return this.wins[i]
}
/**
* Your TopVotedCandidate object will be instantiated and called as such:
* obj := Constructor(persons, times);
* param_1 := obj.Q(t);
*/
# Accepted solution for LeetCode #911: Online Election
class TopVotedCandidate:
def __init__(self, persons: List[int], times: List[int]):
cnt = Counter()
self.times = times
self.wins = []
cur = 0
for p in persons:
cnt[p] += 1
if cnt[cur] <= cnt[p]:
cur = p
self.wins.append(cur)
def q(self, t: int) -> int:
i = bisect_right(self.times, t) - 1
return self.wins[i]
# Your TopVotedCandidate object will be instantiated and called as such:
# obj = TopVotedCandidate(persons, times)
# param_1 = obj.q(t)
// Accepted solution for LeetCode #911: Online Election
use std::collections::HashMap;
struct TopVotedCandidate {
times: Vec<i32>,
leaders: Vec<i32>,
}
impl TopVotedCandidate {
fn new(persons: Vec<i32>, times: Vec<i32>) -> Self {
let n = persons.len();
let mut hm: HashMap<i32, usize> = HashMap::new();
let mut leader: (usize, i32) = (0, 0);
let mut leaders = vec![];
for i in 0..n {
let count = hm.entry(persons[i]).or_default();
*count += 1;
if *count >= leader.0 {
leader = (*count, persons[i]);
}
leaders.push(leader.1);
}
TopVotedCandidate { times, leaders }
}
fn q(&self, t: i32) -> i32 {
let i = match self.times.binary_search(&t) {
Ok(i) => i,
Err(i) => i - 1,
};
self.leaders[i]
}
}
#[test]
fn test() {
let persons = vec![0, 1, 1, 0, 0, 1, 0];
let times = vec![0, 5, 10, 15, 20, 25, 30];
let tvc = TopVotedCandidate::new(persons, times);
assert_eq!(tvc.q(3), 0);
assert_eq!(tvc.q(12), 1);
assert_eq!(tvc.q(25), 1);
assert_eq!(tvc.q(15), 0);
assert_eq!(tvc.q(24), 0);
assert_eq!(tvc.q(8), 1);
}
// Accepted solution for LeetCode #911: Online Election
class TopVotedCandidate {
private times: number[];
private wins: number[];
constructor(persons: number[], times: number[]) {
const n = persons.length;
this.times = times;
this.wins = new Array<number>(n).fill(0);
const cnt: Array<number> = new Array<number>(n).fill(0);
let cur = 0;
for (let i = 0; i < n; ++i) {
const p = persons[i];
cnt[p]++;
if (cnt[cur] <= cnt[p]) {
cur = p;
}
this.wins[i] = cur;
}
}
q(t: number): number {
const search = (t: number): number => {
let l = 0,
r = this.times.length;
while (l < r) {
const mid = (l + r) >> 1;
if (this.times[mid] > t) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
};
const i = search(t) - 1;
return this.wins[i];
}
}
/**
* Your TopVotedCandidate object will be instantiated and called as such:
* var obj = new TopVotedCandidate(persons, times)
* var param_1 = obj.q(t)
*/
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.