数组中出现次数超过一半的数字
方法1.
(1)快排中的 partition()的功能是找到 pivot ,并且将pivot放在排好序的最终位置。(2)所以,如果有次数超过一半的数字,那么对数组排序后,中间的元素一定是那个元素。
所以使用partition()的返回值进行判断,
如果 pivot < middle, 快排pivot之后的元素,
pivot > middle, 快排pivot之前的元素。
直到 pivot == middle。
然后再判断该元素出现的次数是否超过一半。
!!问题:
(1) 会改变原数组的值,因为partition()会交换
方法2. 只遍历, 不交换
遍历数组,保持2个变量。数字a, 次数b。如果某个数出现超过一半,那么也就是说,其他说出现次数之和不超过一半。
初始
a = array[0];
b = 1;
遍历数组,
(1)如果 a[i] == a,++b
else --b;
(2)如果 0 == b, a[i], b= 1;
之后还得需要检查一下base次数是否大于一半
a ---- 要统计的数。
b ---- 其他数出现的次数。
代码
int qPartition(int *a, int low, int high)
{
int pivot = a[low];
while(low < high)
{
while(low < high && a[high] >= pivot) --high;
a[low] = a[high];
while(low < high && a[low] <= pivot) ++low;
a[high] = a[low];
}
a[low] = pivot;
return low;
}
bool isMoreThanHalf(int *a, int length, int result)
{
int cnt = 0;
int i;
for(i = 0; i < length; ++i)
{
if(result == a[i])
++cnt;
}
return cnt * 2 > length;
}
bool isArrayVaild(int *a, int length)
{
if(NULL == a || length <= 0)
return false;
return true;
}
int RESULT_FLAG = 0;
/// 方法1.
int MoreThanHalf(int *a, int length)
{
if(NULL == a || length <= 0)
return 0;
int middle = length >> 1;
int part = qPartition(a, 0, length - 1);
while(part != middle)
{
if(part < middle)
{
part = qPartition(a, part + 1, length - 1);
}
else
{
part = qPartition(a, 0, part - 1);
}
}
if(isMoreThanHalf(a, length, a[middle]))
return a[middle];
else
return 0;
}
/// 方法2.
int MoreThanHalf_1(int *a, int length)
{
if(!isArrayVaild(a, length))
{
RESULT_FLAG = -2;
return -1;
}
int base, num, i;
base = a[0];
num = 1;
for(i = 1; i < length; ++i)
{
if(0 == num)
{
base = a[i];
num = 1;
}
else if(base == a[i])
++num;
else
--num;
}
if(isMoreThanHalf(a, length, base))
RESULT_FLAG = 0;
else
RESULT_FLAG = -1;
return base;
}
测试
void test()
{
///int a[] = {1,2,3,2,2,2,5,4,2};
int a[] = {2,3,1,1,1};
int length = sizeof(a) / sizeof(*a);
///cout<<MoreThanHalf(a, length)<<endl;
int result = MoreThanHalf_1(a, length);
if(!RESULT_FLAG)
cout<<result<<endl;
else
cout<<"not have one :: "<<result<<endl;
}