0 结果
1 题目
2 思路
2.1 思路1(暴力解:双重枚举)
双重枚举判断每个元素是否是主元素。
#include <cstdio>
#include <cstdlib>
const int n = 8;
int ans(int A[], int n){
int cnt;
for(int i = 0;i < n;i++){
cnt = 0;
for(int j = 0; j < n;j++){
if(A[i] == A[j]) cnt++;
if(cnt > n/2) return A[i];
}
}
return -1;
}
int main(){
int A[] = {0,5,5,3,5,1,5,7};//{0,5,5,3,5,7,5,5};
printf("A:");
for (int i = 0; i < n; ++i) {
printf("%d ", A[i]);
}
printf("\n%d", ans(A, n));
return 0;
}
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1)
2.2 思路2(较优解:排序)
对原序列使用快速排序得到升序序列后,扫描一趟数组,如果同值元素左右相距距离大于n/2,则存在主元;反之,则不存在。
#include <cstdio>
#include <cstdlib>
#include <algorithm>
void Qsort(int A[], int L, int R){
if(L >= R) return;
int pivot , i = L, j = R;
std::swap(A[L], A[rand()%(R - L + 1) + L]);
pivot = A[L];//比较基准元素
while (i < j){
while(i < j && A[j] > pivot) j--;
while(i < j && A[i] <= pivot) i++;
if(i < j) std::swap(A[i], A[j]);
}
std::swap(A[i], A[L]);
Qsort(A, L, i - 1);
Qsort(A, i + 1, R);
}
int ans(int A[], int n){
Qsort(A, 0, n - 1);
int L = 0;//同值最左边的元素位置
for(int i = 0;i < n;i++){
if(A[i] != A[L]){//遇到新元素A[i]
if(i - L > n/2)
return A[L];
L = i;
}
}
return -1;
}
int main(){
int A[] = {0,5,5,3,5,7,5,5};//{0,5,5,3,5,1,5,7};
int n = sizeof(A)/sizeof(A[0]);
printf("A:");
for (int i = 0; i < n; ++i) {
printf("%d ", A[i]);
}
printf("\n%d", ans(A, n));
return 0;
}
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
2.3 思路3(较优解:空间换时间)
使用hash映射打表,每出现一次次数加1,如果次数有超过n/2,则存在主元素,反之,则不存在。(缺点:需要辅助数组)。
#include <cstdio>
#include <cstring>
int ans(int A[], int n){
int cnt[n];
memset(cnt, 0, sizeof(cnt));
for(int i = 0;i < n;i++)//统计数字出现的次数
cnt[A[i]]++;
for(int i = 0;i < n;i++){//寻找主元
if(cnt[i] > n/2)
return i;
}
return -1;
}
int main(){
int A[] = {0,5,5,3,5,1,5,7};//{0,5,5,3,5,7,5,5};
int n = sizeof(A)/sizeof(A[0]);
printf("A:");
for (int i = 0; i < n; ++i) {
printf("%d ", A[i]);
}
printf("\n%d", ans(A, n));
return 0;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
2.4. 思路4(最优解:技巧——两两抵消)
两两相互抵消。如果数组中存在大于一般的相同元素,首先假设第一个元素为主元素的候选元素【统计个数为1】,如果目前元素统计的个数大于0,遇到相同的数字——个数加1,不同的数字——个数减1;当元素统计的个数为0时,将遇到的数字变更为候选的主元素。循环结束时,遍历整个数组来统计候选主元素在数组中的个数,如果大于n/2,则存在主元素,反之则不存在。
#include <cstdio>
#include <cstdlib>
int ans(int A[], int n){
int num = A[0], cnt = 1;
for (int i = 1; i < n; ++i) {
if(A[i] == num){
cnt++;
}else{
if(cnt > 0){
cnt--;
}else{
num = A[i];
cnt = 1;
}
}
}
cnt = 0;
for (int j = 0; j < n; ++j) {
if(num == A[j]){
cnt++;
}
}
if(cnt > n/2){
return num;
}else{
return -1;
}
}
int main(){
int A[] = {0,5,5,3,5,1,5,7};//{0,5,5,3,5,7,5,5};
int n = sizeof(A)/sizeof(A[0]);
printf("A:");
for (int i = 0; i < n; ++i) {
printf("%d ", A[i]);
}
printf("\n%d", ans(A, n));
return 0;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)