查找数组中出现次数超过数组长度一半的数字

题目:
数组中一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如:
输入一个长度为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;
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/baidu_37964071/article/details/80456994