简述摩尔投票
摩尔投票一般是用作求解序列“众数”(这和传统意义的众数不同,为了方便表示我加引号)(严格大于数个数的 \(\frac{1}{2}\))**的问题,时间复杂度为 \(\mathcal O(n)\),但是空间复杂度为 \(\mathcal O(1)\)!
考虑到是严格大于,所以答案至多只有 \(1\) 个。
一下考虑有解。
我们考虑把序列看作民众选举,通过抵消来求解这个数。
设当前这个严格“众数”为 \(num\),票数为 \(cnt\),当前这个人投了 \(x\):
-
\(cnt = 0\),那么 \(num'\) 已经抵消完了,此时 \(num \gets x\),\(cnt \gets 1\)。
-
\(num \neq x\),说明这个人投了别人(可恶)!所以抵消,\(cnt \gets cnt - 1\)。
-
\(num = x\),又有人投票了,那么 \(cnt\gets cnt + 1\)。
感性理解,我们可以按照序列重新从小到大排序,如果存在严格大于 \(\lfloor{\frac{n}{2}}\rfloor\) 的 \(num\),即使它和别人抵消,也至少会剩下 \(1\) 个。
并且我们发现,如果将序列分成前一半和后一半,设前一半的答案为 \(num1\),次数为 \(cnt1\);后一半的答案为 \(num2\),次数为 \(cnt2\)。
那么众数 \(num\) 一定是次数较多的那一个。
比如 \(a = [1,2,2,2,2,2,1,1,1,1,1,1,1,1,5]\),我们划分成 \(b=[1,2,2,2,2,2]\),\(c=[1,1,1,1,1,1,1,1,5]\),那么 \(num1=2\),\(cnt1=5\),\(num2=1\),\(cnt2=8\),正确答案为 \(1\)。
我们发现,这样抵消了答案还是 \(1\),剩余 \(cnt2=8-5=3>0\)!
考虑求解出现次数严格大于 \(\lfloor\frac{n}{k}\rfloor\) 的数(\(1\le n\le 10^6\),\(1\le k\le 10\))。
可以证明,答案最多为 \(k - 1\) 个。
上面我们只有一个存储变量 \(num\),现在我们增加到 \(k-1\) 个存储变量,可以把它们放到数组里,然后对于这 \(k-1\) 个数都做一遍上面的三种情况即可。
时间复杂度为 \(\mathcal O(nk)\),但是空间复杂度为 \(\mathcal O(k)\),比普通排序或者离散化做的空间复杂度 \(\mathcal O(n)\) 优秀很多!
考虑求解区间严格“众数”。
上面已经总结了:
并且我们发现,如果将序列分成前一半和后一半,设前一半的答案为 \(num1\),次数为 \(cnt1\);后一半的答案为 \(num2\),次数为 \(cnt2\)。
那么众数 \(num\) 一定是次数较多的那一个。
因此我们只要把这些信息放到线段树上,对于每次询问的 \([L,R]\),直接查询。
注意到不同的只有合并过程,也并不难写。
-
这样时间复杂度为 \(\mathcal O(T\log n)\),空间复杂度为 \(\mathcal O(n)\)(不要忘了 \(4\) 倍空间,这里只是省略常数),其中 \(T\) 为询问次数。
-
朴素的排序做法和离散化做法时间复杂度为 \(\mathcal O(T(n+\log n))\),复杂度升天,空间复杂度也就优化到了摩尔投票法的 \(\frac{1}{4}\)。
本文来自博客园,作者:2021zjhs005,转载请注明原文链接:https://www.cnblogs.com/2021zjhs005/p/18954958

浙公网安备 33010602011771号