剑指offer面试题39--数组中出现次数超过一半的数字

题目描述

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

思路一:

分析:数组中若一个数字出现次数超过一半,则一定比其他所有元素出现次数的和多,若从数组头开始遍历,令num=array[0],设一个count变量,初值1,遇到相同元素count加一,不同元素count减1,,当count==0时候,更新num令它等于新遇到的元素值。最终,我们需要求的出现次数超过一半的元素一定是最后一次让count等于1对应的元素值。整个算法的时间复杂度是O(n)

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {

        int n = numbers.size();
        if (n == 0) return 0;
         
        int num = numbers[0], count = 1;
        for (int i = 1; i < n; i++) {
            if (numbers[i] == num) count++;
            else count--;
            if (count == 0) {
                num = numbers[i];
                count = 1;
            }
        }
        // 输入数组可能不存在个数超过一半的元素,若不存在,返回0
        count = 0;
        for (int i = 0; i < n; i++) {
            if (numbers[i] == num) count++;
        }
        if (count * 2 > n) return num;
        return 0;
        
    }
};

思路二:

基于Partition函数的时间复杂度是O(n)的算法

分析:易知,若数组中有出现次数超过一半的元苏,若将数组排序,数组中间的数字一定是出现次数超一半的数字,排序的时间复杂度是O(nlogn)

基于Partition函数的时间复杂度是O(n)的算法

先从数组中随机选一个元素,然后调整数组中数字顺序,使比选中后数字小的放选中数的左边,比选中数大的放它右边,如果选中数字经过一次Partition后的下标刚好是n/2,则待求的数字就是Partition后的array[n/2];若随机选的数字在Partition后下标大于n/2,则中位数(待求数字)应该在Partition后随机数的左边 ,否则在右边。递归求解


#include <algorithm>
#define random(a,b) (rand()%(b-a+1)+a)

class Solution {
public:
    int Partition(vector<int> data, int length, int start, int end)
{
    int pivot = random(start, end);
    swap(data[pivot], data[end]);
        int small = start - 1;
    for (int index = start; index<end; index++)
    {
        //如果index所指向的元素小于pivot枢纽元素的话,index和small游标一起向右走,当index所指向的元素大于或者等于pivot枢纽元素的话,只是index自己向右走,small不动,这样的话index走啊走啊 发现有一个小于pivot枢纽元素的时候,将此元素与small所指向的元素互换
        if (data[index]<data[end])//此处若改成大于号则从大到小排
        {
            ++small;
            if (small != index)
            {
                swap(data[index], data[small]);
            }
            
        }
        
    }
    ++small;
    //最后把small所指向元素与枢纽元素pivot互换
    swap(data[small], data[end]);
         return small;
}

    int MoreThanHalfNum_Solution(vector<int> numbers) {
          int length=numbers.size();
        if(length==0)
            return 0;
        
        int middle=length>>1;
        int start=0;
        int end=length-1;
        
        int randomIndex=Partition(numbers,length,start,end);
        while(randomIndex!=middle)
        {
              if(randomIndex>middle)
              {
                  end=randomIndex-1;
                  randomIndex=Partition(numbers,length,start,end);
              }
            
            else
            {
               start=randomIndex+1;
                randomIndex=Partition(numbers,length,start,end);
            }
        }
        
        int result=numbers[middle];
        int times=1;//验证下上面的到的result是不是在数组中出现次数超过一半
        for(int i=1;i<length;++i)
        {
             if(numbers[i]==result)
                 times++;
            
        }
        
        if(times*2<=length)
            return 0;
        
        else
            return result;
    }
};

关于快速排序和Partition函数,看我的这篇博文

https://blog.csdn.net/qq_34793133/article/details/80610016

关于C++产生随机数

https://blog.csdn.net/qq_34793133/article/details/80767076

猜你喜欢

转载自blog.csdn.net/qq_34793133/article/details/81196394
今日推荐