出现次数超过一半的数字
题目
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为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对应的数字则为符合题目要求的数字。
more_half_num函数的作用是:1.如果数组中有超过出现次数超过数组长度一半的数字,返回该数字2.否则返回最有一个元素,所以最后要用check_more_than_half该函数检测返回的元素的个数是否超过函数的一半长度。
class Solution { public: int majorityElement(vector<int>& nums) { if (nums.size() <= 2) { return nums[0]; } int flag = nums[0]; int count = 1; for (int i = 1; i < nums.size(); ++i) { if (flag == nums[i]) { ++count; } else { if (count == 0) { flag = nums[i]; count = 1; } else { --count; } } } return flag; } };
三
定义一个栈,先把数组的第一个元素入栈
- 如果下一个元素与栈顶元素相同,下一个元素入栈
- 否则,栈顶元素出栈
- 如果最后栈不为空,栈顶元素就是重复超过一半的数字(而且最后栈中的元素的个数就是此元素超过其它元素个数总和的数)
#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; }