题目:
数组中一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如:
输入一个长度为9的数组{1,2,3,2,2,2,5,4,2},由于2出现的次数为5次,超过数组的一半,因此输出的结果是2。
我们可以这样考虑:
有如下解法:
方案一:
考虑一下,如果某数出现的次数大于数组长度的一半,那么若我们将数组中所有数字排序的话,中间的数肯定就是要求的数。我们用快排。
随机选中一个数字key,排序后再Key左边的数字都比key小,在key右边的数字都比key大。有关快排解释详情见[链接]。(https://blog.csdn.net/baidu_37964071/article/details/79439679)
如果选中的数在的下标刚好是第n/2的数字,那么这个数字就是中位数.如果下标大于n/2,那么中位数,在它的左边,如果下标小于n/2,那么中位数在它右边.这是一个典型的递归算法。
时间复杂度为O(n)。
下面是代码:
//快排
int Partition(int *array, int length, int left, int right)
{
int key = array[right];
while (left < right)
{
if (left < right&&array[left] <= key)
{
++left;
}
array[right] = array[left];
if (left < right&&array[right] >= key)
{
--right;
}
array[left] = array[right];
}
array[left] = key;
return left;
}
//考虑非法输入
bool CheckInvalidArray(int* num, int length)
{
int Invalid = false;
if (num == NULL || length < 0)
{
Invalid = true;
}
return Invalid;
}
//无符合标准的数
bool CheckMoreThanHalf(int *num, int length, int number)
{
int time = 0;
for (int i = 0; i < length; i++)
{
if (num[i] == number)
time++;
}
bool flag = true;
if (time * 2 <= length)
{
flag = false;
}
return flag;
}
int MoreThanHalfNum(int *num, int length)
{
if (CheckInvalidArray(num, length))
{
return 0;
}
int middle = length >> 1;
int start = 0;
int end = length - 1;
int index = Partition(num, length, start, end);
while (index != middle)
{
if (index > middle)
{
end = index - 1;
index = Partition(num, length, start, end);
}
else
{
start = index + 1;
index = Partition(num, length, start, end);
}
}
int result = num[middle];
if (!CheckMoreThanHalf(num, length, result))
result = 0;
return result;
}
方案二:
考虑一下数组的特点,数组中有一个数字出现的次数超过数组长度的一半,也就相当于大于其他所有数字出现的次数和。
我们可以用数组来遍历,我们需要保存两个值,一个是数字,一个是次数。
我们来分析,当下一个数字和上一个数字相同,那么次数+1;如果下一个数字和上一个数字不同,次数-1;如果次数为0,我们保存下一个数字,并把次数置为1。
那么超过一半的次数的数字,一定是最后一次把次数设置为1的数字。
这样就可以在O(n)的时间复杂度求出这个数。
代码如下:
int MoreThanHalfNum(int *num, int length)
{
if (CheckInvalidArray(num, length))
return 0;
int result = num[0];
int count = 0;
for (int i = 0; i < length; i++)
{
if (count == 0)
{
result = num[i];
count = 1;
}
else if (num[i] == result)
{
count++;
}
else
{
count--;
}
}
if (!CheckMoreThanHalf(num, length, result))
{
result = 0;
}
return result;
}
这里也需要检验数组的输入是否有效,这里不再重复。
测试一下:
int main()
{
int array[]={ 1, 2, 3, 2, 2, 2, 5, 4, 2 };
cout << MoreThanHalfNum(array,9)<<endl;
system("pause");
return 0;
}