出现次数超过一半的数字
Posted tianzeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了出现次数超过一半的数字相关的知识,希望对你有一定的参考价值。
题目
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
思路
一
- 数组中出现次数超过一半,所以数组中间的数字一定就是那个出现次数超过数组一半的数字
- 基于快排算法中的Partition函数,使得比选中的数字小的数字都在它左边,比选中的数字大的数字都在它的右边
- 如果选中的数字的下标刚好是n/2,那么这个数字就是数组中的中位数
- 如果它的下标大于n/2,那么中位数应该位于它的左边,继续在左边寻找
- 如果它的下标小于n/2,那么中位数应该位于它的右边,继续在右边寻找
#include <iostream> #include <vector> #include <algorithm> using namespace std; class Solution { public: int more_half_num(vector<int> &v); int partition(vector<int> &v,int start,int end); bool check_more_than_half(vector<int> &v,int num); bool check_valid(vector<int> &v); }; int Solution::more_half_num(vector<int> &v) { if(!check_valid(v)) return 0x3f3f; int mid=v.size()>>1; int start=0; int end=v.size()-1; int index=partition(v,start,end); while(index!=mid) { if(index>mid) index=partition(v,start,index-1); else index=partition(v,index+1,end); } int result=v[mid]; if(check_more_than_half(v,result)) return result; return 0x3f3f; } bool Solution::check_more_than_half(vector<int> &v,int num) { int count=0; for(auto k:v) { if(k==num) ++count; } if(count<<1<v.size()) return false; return true; } int Solution::partition(vector<int> &v,int start,int end) { if(v.empty()||v.size()<=0||start<0||end>=v.size()) { cerr<<"invalid parameter"<<endl; return -1; } int t=v[start]; while(start<end) { while(start<end&&t<=v[end]) --end; if(start<end) v[start++]=v[end]; while(start<end&&t>v[start]) ++start; if(start<end) v[end--]=v[start]; } v[start]=t; return start; } bool Solution::check_valid(vector<int> &v) { if(v.empty()||v.size()<0) return false; return true; } int main() { vector<int> v{1,2,3,6,6,6,6,6,5}; Solution s; int t=s.more_half_num(v); if(t!=0x3f3f) cout<<t<<endl; return 0; }
二
数组中出现次数超过一半,所以该数字出现的次数超过数组长度的一半,也就是它出现的次数比其他所有数字出现次数的和还要多;遍历数组的时候保存两个值:一个是数字,一个是次数。如果下一个数字和保存的数字相同,则次数加1;不相同则减1;如果次数为0,则保存下一个数字,次数设置为1。因为数字超过一半,所以最后一次数字大于1对应的数字则为符合题目要求的数字。
#include <iostream> #include <vector> #include <algorithm> using namespace std; class Solution { public: int more_half_num(vector<int> &v); bool check_more_than_half(vector<int> &v,int num); bool check_valid(vector<int> &v); }; int Solution::more_half_num(vector<int> &v) { if(!check_valid(v)) return 0x3f3f; int result=v[0]; int count=1; for(int i=1;i<v.size();++i) { if(count==0) { result=v[i]; count=1; } else if(result==v[i])//如果记录的值与统计值相等,记数值增加 ++count; else//如果不相同就减少,相互抵消 --count; } if(check_more_than_half(v,result)) return result; return 0x3f3f; } bool Solution::check_more_than_half(vector<int> &v,int num) { int count=0; for(auto k:v) { if(k==num) ++count; } if(count<<1<v.size()) return false; return true; } bool Solution::check_valid(vector<int> &v) { if(v.empty()||v.size()<0) return false; return true; } int main() { vector<int> v{6,1,1,6,2,6,3,6,6,5}; Solution s; int t=s.more_half_num(v); if(t!=0x3f3f) cout<<t<<endl; return 0; }
三
定义一个栈,先把数组的第一个元素入栈
- 如果下一个元素与栈顶元素相同,下一个元素入栈
- 否则,栈顶元素出栈
- 如果最后栈不为空,栈顶元素就是重复超过一半的数字(而且最后栈中的元素的个数就是此元素超过其它元素个数总和的数)
#include <iostream> #include <stack> #include <vector> using namespace std; class Solution { public: int more_half_num(vector<int> &v); }; int Solution::more_half_num(vector<int> &v) { if(v.empty()||v.size()<0) return 0x3f3f; stack<int> s; s.push(v[0]); for(int i=1;i<v.size();++i) { if(!s.empty()) { if(s.top()==v[i]) s.push(v[i]); else s.pop(); } else s.push(v[i]); } if(!s.empty()) return s.top(); return 0x3f3f; } int main() { vector<int> v{1,2,3,6,6,6,6,6,5}; Solution s; int t=s.more_half_num(v); if(t!=0x3f3f) cout<<t<<endl; return 0; }
以上是关于出现次数超过一半的数字的主要内容,如果未能解决你的问题,请参考以下文章
Java 剑指offer(39) 数组中出现次数超过一半的数字