首先这道算法题并不是很难,看过剑指Offer的同学都知道这是里面的一道题。在各大公司的面试中也是经常被用到的,今天我们就采用最常规的方法来实现一下。
首先有人会想到,如果能把数组排序后,那么中间的那个数字就是超过一半的那个数字了(如果存在的话)。当然排序较快的复杂度为O(nlogn).这种方法完全可以实现,但未必是最好的。
因此,面试中最常规的解法就是使用快速排序中的Partition划分函数来解决该问题。如果有对快速排序不了解的,可以参考这篇博客http://blog.csdn.net/CHENYUFENG1991/article/details/50628254 。每进行一次Partition函数划分后,就会把某一个基准数放到它正确的index上,前面的都小于这个基准数,后面的都大于这个基准数。如果恰好某一次Partition后,这个index在数组的中间位置,那么这个位置的数字就是超过数组一半的数字。快速排序也是基于这种思路来进行排序的。所以我们需要做的就是递归的调用Partition,直到找到index == mid位置。代码上传至 https://github.com/chenyufeng1991/MoreThanHalf 。
// 数组中出现次数超过一半的数字
// 使用Partition划分
#include <stdio.h>
#include <stdlib.h>
void MoreThanHalf(int *arr, int start, int end);
int Partition(int *arr, int start, int end);
void CheckNumber(int *arr, int length, int num);
int main(int argc, const char * argv[])
{
// 1 1 4 4 4 7 7 7 7
int array[] = {3,1,3,7,3,3,7,3,7};
MoreThanHalf(array, 0 ,8);
return 0;
}
// 核心代码
void MoreThanHalf(int *arr, int start, int end)
{
int mid = (start + end) / 2;
int index = Partition(arr, start, end);
while (index != mid)
{
if (index < mid)
{
index = Partition(arr, index + 1, end);
}
else
{
// index > mid
index = Partition(arr, start, index - 1);
}
}
if (index == mid)
{
printf("数组中间的数字为:%d\n",arr[index]);
CheckNumber(arr, 9, arr[index]);
return;
}
}
int Partition(int *arr, int start, int end)
{
int i = start, j = end, x = arr[start];
while (i < j)
{
while (i < j && arr[j] >= x)
{
j--;
}
if (i < j)
{
arr[i++] = arr[j];
}
while (i < j && arr[i] < x)
{
i++;
}
if (i < j)
{
arr[j--] = arr[i];
}
}
arr[i] = x;
return i;
}
// 检查该数是否真的是超过一半的,也就是为了验证原先输入的数组中是否真的存在某个数超过数组长度一半
void CheckNumber(int *arr, int length, int num)
{
int count = 0;
for (int i = 0; i < length; i++)
{
if (arr[i] == num)
{
count++;
}
}
if (count > length / 2)
{
printf("超过数组一半的数字是:%d\n",num);
}
else
{
printf("不存在超过数组一半的数字\n");
}
return ;
}