[九度][何海涛] 数组中出现次数超过一半的数字
- 题目描述:
-
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
- 输入:
-
每个测试案例包括2行:
第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数。
第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,1000000000]。
- 输出:
-
对应每个测试案例,输出出现的次数超过数组长度的一半的数,如果没有输出-1。
- 样例输入:
-
9 1 2 3 2 2 2 5 4 2
- 样例输出:
-
2
这道题可以分两种方法做。方法1:类似于消除原理,既然某个数字大于长度的一半,那么我们就遍历数组,如果两个数不相等则消除,最后剩下的数就是我们要的。当然如果不存在这样的数,这是不行的。所以最后要再遍历一遍验证这个数的出现次数是否大于数组的一半。1 #include <iostream> 2 using namespace std; 3 4 bool check(int num[], int key, int n) 5 { 6 int count = 0; 7 for(int i = 0; i < n; i++) 8 count += (key == num[i]); 9 10 return 2 * count > n; 11 } 12 13 int main() 14 { 15 int firstCount = 0; 16 int secondCount = 0; 17 int firstNum; 18 int secondNum; 19 int num[100000]; 20 21 int n; 22 while(cin >> n) 23 { 24 firstCount = 0; 25 secondCount = 0; 26 for(int i = 0; i < n; i++) 27 { 28 cin >> num[i]; 29 if (firstCount > 0 && num[i] == firstNum) 30 { 31 firstCount++; 32 } 33 else if (secondCount > 0 && num[i] == secondNum) 34 { 35 secondCount++; 36 } 37 else if (firstCount == 0) 38 { 39 firstNum = num[i]; 40 firstCount = 1; 41 } 42 else if (secondCount == 0) 43 { 44 secondNum = num[i]; 45 secondCount = 1; 46 } 47 else 48 { 49 int minCount = min(secondCount, firstCount); 50 secondCount -= minCount; 51 firstCount -= minCount; 52 if (secondCount == 0) 53 { 54 secondNum = num[i]; 55 secondCount = 1; 56 } 57 else 58 { 59 firstNum = num[i]; 60 firstCount = 1; 61 } 62 } 63 } 64 65 int minV = min(firstCount, secondCount); 66 firstCount -= minV; 67 secondCount -= minV; 68 69 if (firstCount > 0) 70 { 71 if (check(num, firstNum, n)) 72 cout << firstNum << endl; 73 else 74 cout << -1 << endl; 75 } 76 else if (secondCount > 0) 77 { 78 if (check(num, secondNum, n)) 79 cout << secondNum << endl; 80 else 81 cout << -1 << endl; 82 } 83 else 84 cout << -1 << endl; 85 } 86 }
方法2:用qsort的partition的方法找出第k大数,k就是数组中间的数,对于n为偶数是中间两个的任意一个数,奇数的话就只有一个。那么,因为数的个数超过一半,那么中间那个数肯定是超过一半的那个数,否则这个数就不存在了。最后遍历一遍数组来验证一下。partition的平摊复杂度为O(n)。最后算法总体复杂度O(n)
1 #include <iostream> 2 #include <ctime> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 void partition(int num[], int left, int right, int k) 8 { 9 if (left >= right) 10 return; 11 12 int randNum = left + (rand() % (right - left + 1)); 13 14 int t = num[left]; 15 num[left] = num[randNum]; 16 num[randNum] = t; 17 18 int i = left; 19 int j = right; 20 21 int key = num[left]; 22 23 while(i <= j) 24 { 25 if (num[i] <= key) 26 i++; 27 else 28 { 29 int t = num[j]; 30 num[j] = num[i]; 31 num[i] = t; 32 33 j--; 34 } 35 } 36 37 num[left] = num[j]; 38 num[j] = key; 39 40 if (j == k) 41 return; 42 else 43 { 44 partition(num, left, j - 1, k); 45 partition(num, j + 1, right, k); 46 } 47 } 48 49 int main() 50 { 51 int n; 52 int num[100000]; 53 54 while(cin >> n) 55 { 56 for(int i = 0; i < n; i++) 57 cin >> num[i]; 58 59 srand(time(NULL)); 60 partition(num, 0, n - 1, n / 2); 61 62 int key = num[n / 2]; 63 64 int count = 0; 65 for(int i = 0; i < n; i++) 66 count += (key == num[i]); 67 68 if (2 * count > n) 69 cout << key << endl; 70 else 71 cout << -1 << endl; 72 } 73 }