数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解法1:基于Partition函数的时间复杂度为O(n)的算法。注意最后检查数字出现次数是否真的超过一半。
1 class Solution { 2 public: 3 int Partition(vector<int> &numbers, int begin, int end) 4 { 5 int tmp=numbers[begin]; 6 while(begin<end) 7 { 8 while(begin<end && numbers[end]>=tmp)--end; 9 numbers[begin]=numbers[end]; 10 while(begin<end && numbers[begin]<=tmp)++begin; 11 numbers[end]=numbers[begin]; 12 } 13 numbers[begin]=tmp; 14 return begin; 15 } 16 bool isMoreThanHalf(vector<int> &numbers, int res, int length)//检查 17 { 18 int count=0; 19 for(int idx=0; idx<length; ++idx) 20 { 21 if(numbers[idx]==res)++count; 22 } 23 return count>length/2; 24 } 25 int MoreThanHalfNum_Solution(vector<int> numbers) { 26 int length=numbers.size(); 27 if(length==0)return 0; 28 int begin=0; 29 int end=length-1; 30 while(true) 31 { 32 int mid=Partition(numbers, begin, end); 33 if(mid==length/2)break; 34 if(mid>length/2) 35 { 36 end=mid-1; 37 }else{ 38 begin=mid+1; 39 } 40 } 41 int res=numbers[length/2]; 42 if(isMoreThanHalf(numbers, res, length))return res; 43 else return 0; 44 } 45 };
解法2:遍历,时间复杂度O(n)。保存两个值:数组中一个数字和次数。遍历到下一个数字时,相同次数加一,不同次数减一,次数为零则重新保存。最后存下来的数字就是出现次数超过一半的那个数字。前提是确实存在出现次数超过一半的数字,所以最后也要检查。与第一种方法相比,不会修改原数组的值。
1 class Solution { 2 public: 3 bool isMoreThanHalf(vector<int> &numbers, int val, int length) 4 { 5 int count=0; 6 for(int idx=0; idx<length; ++idx) 7 { 8 if(numbers[idx]==val)++count; 9 } 10 return count>length/2; 11 } 12 int MoreThanHalfNum_Solution(vector<int> numbers) { 13 int length=numbers.size(); 14 if(length==0)return 0; 15 int val=numbers[0]; 16 int count=1; 17 for(int idx=1; idx<length; ++idx) 18 { 19 if(numbers[idx]==val)++count; 20 else --count; 21 if(count==0) 22 { 23 val=numbers[idx]; 24 count=1; 25 } 26 } 27 if(isMoreThanHalf(numbers, val, length))return val;//检查 28 else return 0; 29 } 30 };