主数是指在序列中出现次数超过一定比例的数,假设序列长度为n
,则出现次数大于n/k
的数最多有k-1
个。
求主数使用投票算法,时间复杂度为$O(n)$,空间复杂度为$O(1)$。
找出数组arr[n]
中出现次数大于n/2
的数(最多有1个),pick
为候选的数,vote
表示其被抵消之后的票数(初始化为0)。
算法分为两个步骤,第一步选出pick
,数组的主数如果有,必然是pick
,否则就是没有;然后还需要第二步,判断pick
出现次数是否真的大于n/k
。
for (int i = 0; i < n; i++) {
if (vote > 0 && arr[i] == pick) { // 如果抵消后票数大于0,pick有效,且当前数等于pick,票数++
vote++;
} else if (vote == 0) { // 如果抵消后票数等于0,pick失效,将当前数作为新的pick
pick = arr[i];
vote++;
} else { // 如果抵消后票数大于0,pick有效,但当前数不等于pick,票数--
vote--;
}
}
int cnt = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == pick)
cnt++;
}
if (cnt*2 > n)
// 获得主数pick
找出数组arr[n]
中出现次数大于n/3
的数(最多有2个),pick1 & pick2
为候选的数,vote1 & vote2
表示其被抵消之后的票数(初始化为0)。
算法分为两个步骤,第一步选出pick1 & pick2
,数组的主数如果有,必然在pick1 & pick2
中,否则就是没有;然后还需要第二步,判断pick1 & pick2
出现次数是否真的大于n/k
。
for (int i = 0; i < n; i++) {
if (vote1 > 0 && arr[i] == pick1) { // 如果抵消后票数大于0,pick有效,且当前数等于pick,票数++
vote1++;
} else if (vote2 > 0 && arr[i] == pick2) {
vote2++;
} else if (vote1 == 0) { // 如果抵消后票数等于0,pick失效,将当前数作为新的pick
pick1 = arr[i];
vote1++;
} else if (vote2 == 0) {
pick2 = arr[i];
vote2++;
} else { // 如果抵消后票数大于0,pick有效,但当前数不等于pick,票数--
vote1--;
vote2--;
}
}
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == pick1)
cnt1++;
else if (arr[i] == pick2)
cnt2++;
}
if (cnt1*3 > n)
// 获得主数pick1
else if (cnt2*3 > n)
// 获得主数pick2