题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为18的数组{1,0,2,6,1,0,1,1,5,2,1,1,1,3,1,1,5,1}, 由于数组中数字1出现的次数超过数组的长度的一半,因此输出1。
1)最直接的办法是先把数组排序,那么超过一半的元素一定是数组最中间的元素。
2)再深入思考一下就会想到快速排序过程,利用partion找出index==middle时,index对应的值,而不必完全排序。
3)第二种办法比较抽象,设一个变量保存当前值,设一个次数,当前值与下一个值进行比较,如果相等,次数加一,如果不相等,次数减一,如果次数减到0了还是不相等,就把当前值替换掉。
这里只展示了2)、3)的源码,没有数据合理性校验。
#include<iostream>
#include<vector>
using namespace std;
int partion(vector<int>& vec,int low,int high)
{//快速排序的基础
int key = vec[high];
int fast = low;
int slow = low;
while (fast < high)
{
if (vec[fast] <= key)
{
if (fast == slow)
slow++;
}
else
{
if (fast != slow)
{
int tmp = vec[slow];
vec[slow] = vec[fast];
vec[fast] = tmp;
slow++;
}
}
fast++;
}
int tmp = vec[slow];
vec[slow] = vec[high];
vec[high] = tmp;
return slow;
}
int find_half1(vector<int> vec)
{
int length=vec.size();
if (length == 0)
return 0;
int start = 0;
int end = length - 1;
int middle = length >> 1;
int index = partion(vec, start, end);
while (index != middle)
{//中位值肯定是出现次数超过一半的数
if (index > middle)
{
end = index - 1;
index = partion(vec, start, end);
}
else
{
start = index + 1;
index = partion(vec, start, end);
}
}
cout << "index:" << index << endl;
return vec[index];
}
int find_half2(vector<int> vec)
{//设置key和index,如果出现等于key的值,index++,否则index--;
//如果index==0,则更新key的值,因为目标值出现次数超过一半,所以,index必然大于0
int key=vec[0];
int index = 0;
for (int i = 0; i < vec.size(); ++i)
{
if (vec[i] == key)
{
index++;
}
else
{
if (index == 0)
{
key = vec[i];
index++;
}
else
{
index--;
}
}
}
return key;
}
int main()
{
int a[18] = {1,0,2,6,1,0,1,1,5,2,1,1,1,3,1,1,5,1};
vector<int> vec(a, a + 18);//这种容器初始化方式很有用
for (int i = 0; i < vec.size(); ++i)
{
cout << vec[i] << " ";
}
cout << endl << find_half1(vec) << endl;
return 0;
}