《剑指offer》39题—数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
方法1:
用快排算法中的partition函数找到数组中第 n/2 大的数,若将数组排序,则有序数组中 n/2 位置处的数必定为出现次数超过一半的数字。
1 class Solution { 2 public: 3 int MoreThanHalfNum_Solution(vector<int> numbers) { 4 int n = numbers.size(); 5 if(n == 0) 6 return 0; 7 int begin=0, end=n; 8 int index = partition(numbers, 0, n); 9 while(index != n/2){ 10 if(index < n/2) 11 begin = index + 1; 12 else 13 end = index; 14 index = partition(numbers, begin, end); 15 } 16 17 int cnt = 0; 18 for(int i=0; i<n; ++i){ 19 if(numbers[index] == numbers[i]) 20 ++cnt; 21 } 22 return cnt > numbers.size()/2 ? numbers[index] : 0; 23 } 24 25 int partition(vector<int> arr, int begin, int end){ 26 int pivot = arr[begin]; 27 while(begin < end){ 28 while(begin < end && arr[--end] >= pivot); 29 arr[begin] = arr[end]; 30 while(begin < end && arr[++begin] <= pivot); 31 arr[end] = arr[begin]; 32 } 33 arr[begin] == pivot; 34 return begin; 35 } 36 };
方法2:
如果有符合条件的数字,则它出现的次数比其他所有数字出现的次数和还要多。
在遍历数组时保存两个值:一是数组中一个数字,一是次数。遍历下一个数字时,若它与之前保存的数字相同,则次数加1,否则次数减1;若次数为0,则保存下一个数字,并将次数置为1。遍历结束后,所保存的数字即为所求。然后再判断它是否符合条件即可。
1 class Solution {
2 public:
3 int MoreThanHalfNum_Solution(vector<int> numbers) {
4 if(numbers.size() == 0)
5 return 0;
6 int majority = numbers[0], cnt = 1;
7 for(int i=1; i<numbers.size(); ++i){
8 if(cnt == 0){
9 majority = numbers[i];
10 cnt = 1;
11 }
12 else
13 cnt = numbers[i]==majority ? cnt+1 : cnt-1;
14 }
15
16 cnt = 0;
17 for(int i=0; i<numbers.size(); ++i){
18 if(majority == numbers[i])
19 ++cnt;
20 }
21 return cnt > numbers.size()/2 ? majority : 0;
22 }
23 };