911. 在线选举
LeetCode: 911. 在线选举
中 等 \color{#FFB800}{中等} 中等
给你两个整数数组
persons
和times
。在选举中,第i
张票是在时刻为times[i]
时投给候选人persons[i]
的。
对于发生在时刻t
的每个查询,需要找出在t
时刻在选举中领先的候选人的编号。
在t
时刻投出的选票也将被计入我们的查询之中。在平局的情况下,最近获得投票的候选人将会获胜。
实现TopVotedCandidate
类:
TopVotedCandidate(int[] persons, int[] times)
使用persons
和times
数组初始化对象。int q(int t)
根据前面描述的规则,返回在时刻t
在选举中领先的候选人的编号。
示例:
输入:
["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]]
输出:
[null, 0, 1, 1, 0, 0, 1]
解释:
TopVotedCandidate topVotedCandidate = new TopVotedCandidate([0, 1, 1, 0, 0, 1, 0], [0, 5, 10, 15, 20, 25, 30]);
topVotedCandidate.q(3); // 返回 0 ,在时刻 3 ,票数分布为 [0] ,编号为 0 的候选人领先。
topVotedCandidate.q(12); // 返回 1 ,在时刻 12 ,票数分布为 [0,1,1] ,编号为 1 的候选人领先。
topVotedCandidate.q(25); // 返回 1 ,在时刻 25 ,票数分布为 [0,1,1,0,0,1] ,编号为 1 的候选人领先。(在平局的情况下,1 是最近获得投票的候选人)。
topVotedCandidate.q(15); // 返回 0
topVotedCandidate.q(24); // 返回 0
topVotedCandidate.q(8); // 返回 1
提示:
- 1 <= persons.length <= 5000
- times.length == persons.length
- 0 <= persons[i] < persons.length
- 0 <= times[i] <= 109
times
是一个严格递增的有序数组- times[0] <= t <= 109
- 每个测试用例最多调用 104 次
q
方法1:哈希表 + 二分查找
我们需要对每个时刻领先的候选人进行预计算,这样在调用 q
函数的时候只要进行查找即可。
定义哈希表 total
,记录每个时刻票数领先的候选人存入 ahead
数组。按题意,如果有多人获得了相等的最高票数,则选择最近那位获得最高票数的。因此我们可以定义一个 top
指针,指向最近获得最高票数的候选人。遍历 persons
数组时,每位候选人的票数自增,total[persons[i]]++
,同时,如果自增后 total[persons[i]] >= total[top]
,就将 top
指向这位候选人,top=persons[i]
。
每个时刻票数最高的候选人已经确定下来了,现在需要解决查找的问题。假设 times
数组为 [5,10]
,查询时刻 8
。由于时刻 8
还没到时刻 10
,因此时刻 8
时的票数最高者就是时刻 5
时的票数最高者。同时,times
数组是严格递增的数组,因此查找的方法可以选择二分查找。
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
class TopVotedCandidate
{
private:
vector<int> times;
const int n;
int *ahead;
public:
TopVotedCandidate(vector<int> &persons, vector<int> ×) : times{times}, n{int(times.size())}, ahead{new int[times.size()]}
{
unordered_map<int, int> total;
int *p = ahead;
int top = -1;
total[top] = -1;
for (const int &person : persons)
{
total[person]++;
if (total[person] >= total[top])
{
top = person;
}
*p = top;
p++;
}
}
int q(int t)
{
int left = 0, right = this->n - 1;
while (left < right)
{
int mid = ((right - left) >> 1) + left + 1;
if (this->times[mid] <= t)
{
left = mid;
}
else
{
right = mid - 1;
}
}
return this->ahead[left];
}
~TopVotedCandidate()
{
delete[] this->ahead;
}
};
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n)。预处理哈希表时要遍历整个数组,时间复杂度为 O ( n ) O(n) O(n);二分查找的时间复杂度为 O ( log n ) O(\log n) O(logn)。因此总时间复杂度为 O ( n + log n ) = O ( n ) O(n+\log n)=O(n) O(n+logn)=O(n)
-
空间复杂度: O ( n ) O(n) O(n)。同上。
参考结果
Accepted
97/97 cases passed (260 ms)
Your runtime beats 33.99 % of cpp submissions
Your memory usage beats 93.1 % of cpp submissions (100.4 MB)