[LeetCode] 911. Online Election 在线选举
In an election, the i
-th vote was cast for persons[i]
at time times[i]
.
Now, we would like to implement the following query function: TopVotedCandidate.q(int t)
will return the number of 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.
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:
At time 3, the votes are [0], and 0 is leading.
At time 12, the votes are [0,1,1], and 1 is leading.
At time 25, the votes are [0,1,1,0,0,1], and 1 is leading (as ties go to the most recent vote.)
This continues for 3 more queries at time 15, 24, and 8.
Note:
1 <= persons.length = times.length <= 5000
0 <= persons[i] <= persons.length
times
is a strictly increasing array with all elements in[0, 10^9]
.TopVotedCandidate.q
is called at most10000
times per test case.TopVotedCandidate.q(int t)
is always called witht >= times[0]
.
在一个选举中第i次投票的情况为persons[i]和times[i],实现一个函数能实现在时间t返回得票数多的lead。
解法:设置一个目前得票最多的变量count,先循环得票人和时间,用hashmap或数组数组统计每个人的得票数,如果次数大于count,则更新count,用数组记录到目前时间得票最多的人(按时间顺序排列的目前得票多的人)。查找某一时间点得票最多的人时,用二分法查找按时间排序的数组。
G家:给一个vote list=[(a, 100), (b, 150), (a, 200)] #(name, timestamp) 和时间T 找T时间之前, 得票数最高的人(或任一得票数最高的人) ex: T=100 -> a, T=150 -> a or b, T=200 -> a. 用map去存每个char对应的频率,如果当前的timestamp小于给定的时间T,就把当前char的频率 + 1, 最后找出map里面value最大的key
Followup1: 多给一个input K, 找T时间之前, Top K 得票数的人. 和上一个题目一样只是找出map里面前K个value最大的key
Followup2: 一样给vote list, K, 但这次给Top K list, 找时间T. 每次添加一张票以后,map里取topk个和topklist比较一下
Java: Basic, easy to understand.
class TopVotedCandidate { int[] leading; int[] time; public TopVotedCandidate(int[] persons, int[] times) { time = times; leading = new int[persons.length]; Map<Integer, Integer> map = new HashMap<>(); for (int n : persons){ map.put(n, 0); } int max = persons[0]; for (int i = 0; i < times.length; i++){ if (i == 0){ map.put(persons[i], 1); leading[i] = persons[i]; }else{ map.put(persons[i], map.get(persons[i]) + 1); if (max != persons[i] && map.get(persons[i]) >= map.get(max)){ max = persons[i]; } leading[i] = max; } //System.out.print(leading[i]); } } public int q(int t) { int i = 0, j = time.length; while (i < j){ int mid = i + (j - i) / 2; if (time[mid] <= t){ i = mid + 1; }else{ j = mid; } } return leading[i - 1]; } }
Java:
class TopVotedCandidate { List<List<Vote>> A; public TopVotedCandidate(int[] persons, int[] times) { A = new ArrayList(); Map<Integer, Integer> count = new HashMap(); for (int i = 0; i < persons.length; ++i) { int p = persons[i], t = times[i]; int c = count.getOrDefault(p, 0) + 1; count.put(p, c); while (A.size() <= c) A.add(new ArrayList<Vote>()); A.get(c).add(new Vote(p, t)); } } public int q(int t) { // Binary search on A[i][0].time for smallest i // such that A[i][0].time > t int lo = 1, hi = A.size(); while (lo < hi) { int mi = lo + (hi - lo) / 2; if (A.get(mi).get(0).time <= t) lo = mi + 1; else hi = mi; } int i = lo - 1; // Binary search on A[i][j].time for smallest j // such that A[i][j].time > t lo = 0; hi = A.get(i).size(); while (lo < hi) { int mi = lo + (hi - lo) / 2; if (A.get(i).get(mi).time <= t) lo = mi + 1; else hi = mi; } int j = Math.max(lo-1, 0); return A.get(i).get(j).person; } } class Vote { int person, time; Vote(int p, int t) { person = p; time = t; } }
Java:
Map<Integer, Integer> m = new HashMap<>(); int[] time; public TopVotedCandidate(int[] persons, int[] times) { int n = persons.length, lead = -1; Map<Integer, Integer> count = new HashMap<>(); time = times; for (int i = 0; i < n; ++i) { count.put(persons[i], count.getOrDefault(persons[i], 0) + 1); if (i == 0 || count.get(persons[i]) >= count.get(lead)) lead = persons[i]; m.put(times[i], lead); } } public int q(int t) { int i = Arrays.binarySearch(time, t); return i < 0 ? m.get(time[-i-2]) : m.get(time[i]); }
Python:
class TopVotedCandidate(object): def __init__(self, persons, times): self.A = [] self.count = collections.Counter() for p, t in zip(persons, times): self.count[p] = c = self.count[p] + 1 while len(self.A) <= c: self.A.append([]) self.A[c].append((t, p)) def q(self, t): lo, hi = 1, len(self.A) while lo < hi: mi = (lo + hi) / 2 if self.A[mi][0][0] <= t: lo = mi + 1 else: hi = mi i = lo - 1 j = bisect.bisect(self.A[i], (t, float('inf'))) return self.A[i][j-1][1]
Python:
def __init__(self, persons, times): self.leads, self.times, count = [], times, {} lead = -1 for t, p in zip(times, persons): count[p] = count.get(p, 0) + 1 if count[p] >= count.get(lead, 0): lead = p self.leads.append(lead) def q(self, t): return self.leads[bisect.bisect(self.times, t) - 1]
Python:
class TopVotedCandidate: def __init__(self, persons, times): votes = collections.defaultdict(int) winner = 0 self.winners = [None] * len(times) self.times = times for i, person in enumerate(persons): votes[person] += 1 if votes[person] >= votes[winner]: winner = person self.winners[i] = winner def q(self, t): return self.winners[bisect.bisect(self.times, t) - 1]
C++:
map<int, int> m; TopVotedCandidate(vector<int> persons, vector<int> times) { int n = persons.size(), lead = -1; unordered_map<int, int> count; for (int i = 0; i < n; ++i) m[times[i]] = persons[i]; for (auto it : m) { if (++count[it.second] >= count[lead])lead = it.second; m[it.first] = lead; } } int q(int t) { return (--m.upper_bound(t))-> second; }
G家:
Give a vote list = [(a, 100), (b, 150), (a, 200)] # (name, timestamp) and time T. Find the highest number of votes (or anyone with the highest number of votes) at T
ex: T = 100 -> a, T = 150 -> a or b, T = 200 -> a
Followup1: give one more input K, find Top K votes at T
Followup2: the same vote list, K, but given the Top K votes list, find the time T.
For the first question, just travers the vote list and if vote.T <= T increment
the vote for person vote.Name. While doing that maximize the vote number.
(O(n*l) time, O(c*l) space, c is the number of candidates, l is average length of name)
follow-up 1: instead of maximizing one, keep the hashtable with votes[person] = no. votes
now, put that into a vector and find the k-th element (using e.g. quicksort's partion
method which is linear)
(O(n*l) time, O(c*l) space)
follow-up 2: I assume given are the top K candidates at a certain time T I have to find.
I have to keep all candidates sorted at each step and compare the top k of them with
the given list. The first part (keeping candidates sorted at each step) can be done
using a balanced binary-tree, so I have O(n*lg(n)+n*l) for creating and maintaining that tree.
(I will have to transpose the name into an integer, and have a nameId instead of the
string in the tree)
Then I would have k compare's per iteration, which is then O(k*n*lg(n)+n*l). the factor k
I can get rid of if I implement the tree in a way, so I monitor when elements enter and
leave the top k. If one of the desired candidates enters top k, I reduce the amount of
candidates I need in top k, if one leaves, I increment back. If that counter (which
starts with k) is 0 I'm done, I found the first time where the desired condition happend.
C:
#include <string> #include <vector> #include <unordered_map> using namespace std; struct Vote { int time_; string name_; }; string find_top_at_time(const vector<Vote>& votes, int time) { unordered_map<string, int> votes_per_name; string max_votes_name; int max_votes_count = -1; for (const Vote& vote : votes) { // O(n) if (vote.time_ <= time) { auto it = votes_per_name.find(vote.name_); // O(l) if (it == votes_per_name.end()) { it = votes_per_name.insert({ vote.name_, 0 }).first; // O(l) compensated } it->second++; if (it->second > max_votes_count) { max_votes_count = it->second; max_votes_name = vote.name_; // O(l) } } } return max_votes_name; }
类似题目:
All LeetCode Questions List 题目汇总