面试题39:数组中出现次数超过一半的数字

题目

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如:输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现5次,超过数组长度一半,因此输出2

解题思路

  • 鲁棒性
    a) 设置全局变量CheckInvalidArray,判断数组是否有效。
bool CheckInvalidArray(SqList *S,int length)
        {
            g_bInputInvalid = false;
            if(S == NULL || length < 0)
            {
                g_bInputInvalid = true;
            }
            return g_bInputInvalid;
        }

b) 检查一个数字出现的次数是否超过数组长度的一半

        bool CheckMoreThanHalf(SqList *S,int length,int result)
        {
            int times = 0;
            for(int i = 1;i<= length;i++)
            {
                if(S->a[i] == result)
                {
                    times++;
                }
            }
            cout << times << endl; 
            bool isMoreThanHalf = true;
            if(times*2 <= length)
            {
                g_bInputInvalid = true;
                isMoreThanHalf  = false;
            }
            return isMoreThanHalf;
        }
  1. 基于Partition函数的时间复杂度为O(n)
    数组的特性:数组中有一个数字出现的次数超过数组长度的一半,那么若把这个数组排序,则排序后位于数组中间的数字一定是出现次数超过数组长度一半的数字,也就是统计学中的中位数。即长度为n的数组中第n/2大的数字。
    即找出middle=length/2的下标的数字,这个时候就用到快速排序算法。如果下标
class Solution
{
    public:
        int Partition(SqList *S,int left,int right,int length)
        {
            
            int povitkey = S->a[left];
            S->a[0] = povitkey;
            while(lefta[left]<=povitkey)
                {
                    left++;
                }
                S->a[left] = S->a[right];
                while(left < right && S->a[right]>=povitkey)
                {
                    right--;
                }
                S->a[right] = S->a[left];
            }
            S->a[left] = povitkey;
            return left;
        }

        int MoreThanHalfNum(SqList *S,int length)
        {
            if(CheckInvalidArray(S,length))
            {
                return 0;
            }
            int middle = length/2;
            int start = 0;
            int end = length-1;
            int index = Partition(S,start,end,length);
            cout << "index:" << index << endl;
            while(index != middle)
            {
                if(index>middle)
                {
                    end = index-1;
                    index = Partition(S,start,end,length);
                }
                else
                {
                    start = index+1;
                    index = Partition(S,start,end,length);
                }
            }
            int result = S->a[middle];
            cout << result << endl;
            if(!CheckMoreThanHalf(S,length,result))
            {
                result = 0;
            }
            return result;
        }

            cout << numInArray<
  1. 根据数组特点找出时间复杂度为O(n)的算法
    考虑遍历数组的时候保存两个值,一个是数组中的一个数字,另一个是次数。当我们遍历到下一个数字的时候:
    如果下一个数字和我们之前保存的数字相同,则次数加1,;
    如果下一个数字和我们保存的数字不同,则次数减一;
    如果次数为0,则需要保存下一个数字,并把次数设为1。
    因为我们要找的数字出现的次数比其他数字出现的次数之和还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。
int MoreThanHalfNum_2(SqList *S,int length)
        {
            
            if(CheckInvalidArray(S,length))
            {
                return 0;
            }
            int numInArray = S->a[1];
            cout<<"第一个元素:" <a[i];
                
                if(times == 0)
                {
                    numInArray = S->a[i];
                    times = 1;
                }
                else if(numInArray == S->a[i])
                {
                    times++;
                }
                else
                {
                    times--;
                }
                cout<<"times:"<

完整代码见GitHub

你可能感兴趣的:(面试题39:数组中出现次数超过一半的数字)