数组中出现次数超过一半的数字

1、题目描述

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

2、代码1:

2.1思路:如果一个数字在数组中出现的次数多于一半,那么这数字一定是整个数组数字的中位数。因为核心点在于如何求数组的中位数。求中位数,最快的就是快快速排序算法。因此这个思路中,核心点就是实现快速排序算法。
2.2代码:

#include<iostream>
#include<vector>
#include<time.h>
using namespace std;

//剑指offer书上O(N)复杂度

//交换vector的两个数
void swap(vector<int>& numbers, int i, int j)
{
    auto temp = numbers[i];
    numbers[i] = numbers[j];
    numbers[j] = temp;
}


//得到一个范围内的随机数
int getRandData(int start, int end)
{
    int index = rand()%(end-start+1)+start;
    return index;
}

//快排程序 -- end是可以取到的最后的下标
int Partition(vector<int>& numbers, int start, int end)
{
    if((start<0)||(end>=numbers.size()))
        return 0;

    //从start到end中随机选择一个数
    int index = getRandData(start,end);
    swap(numbers, index,end);


    int small = start-1;        //指向当前左边有序序列最后一个数,即下一个数就是大于index的数
    for(int i=start;i<end;i++)
    {
        if(numbers[i]<numbers[end])
        {
            small++;
            if(i!=small)
                swap(numbers, i,small);     //交换当前比index大的数和第一个比index小的数
        }
    }

    //交换回index的位置
    ++small;
    swap(numbers, end,small);
    return small;       //返回当前选取的随机数的新的下标
}



//找出中位数
int findMiddleData(vector<int> numbers)
{
    int mid = numbers.size()/2;
    int start = 0;
    int end = numbers.size()-1;
    int index = Partition(numbers, 0, end);
    while(index!=mid)
    {
        if(index<mid)
            index = Partition(numbers, index+1, end);
        else
            index = Partition(numbers, start, index-1);
    }
    return numbers[index];
}

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        if(numbers.empty())
            return 0;
        auto data = findMiddleData(numbers);

        int times=0;
        for(int i=0;i<numbers.size();i++)
            if(numbers[i]==data)
                times++;
        if(times>(numbers.size()/2))
            return data;
        else
            return 0;
    }
};



int main()
{
    srand((unsigned)time(NULL));

    int data[] = {1,2,3,2,2,2,5,4,2};
    vector<int> vec;
    for(int i=0;i<9;i++)
        vec.push_back(data[i]);

    Solution A;
    cout << A.MoreThanHalfNum_Solution(vec) <<endl;

    system("pause");
    return 1;


}

3.3注意的几点:
(1)快速排序算法的实现很关键,重点,无论什么时候快速排序都需要能够很快写出来。
(2)随机选择函数中,srand种子初始化的时候注意,一般srand种子初始化只需要执行一次,不能多次。如果每次取随机数的时候都执行一次种子初始化,可能多次取的随机数都是一样的。典型情况如下:

//得到一个范围内的随机数
int getRandData(int start, int end)
{
    srand((unsigned)time(NULL));  //获取系统时间初始化种子
    int index = rand()%(end-start+1)+start;
    return index;
}

这里每次取随机数都用系统时间做种子初始化,由于函数执行快,那么可能联系调用getRandData函数的时候,time函数的返回的系统时间相同,每次都重新设置了种子,且是相同的种子,因此,得出的随机数是一样的。

3、代码2

3.1思路:遍历数组所有的数据,用一个数据存储一个数组中的值,一个用于存储次数。每次遍历下一个数据的时候,和当前存储的数组中的值进行比较,相同则次数加1,不同则次数减1。第一个数字的时候,次数为1。当遍历中遇到次数为0的时候,把当前遍历的数组的值设置成存储的值,次数设置成1。那么最后出现次数最多的数字一定是最后的那个数据存储的值。但是最后存储的值不一定是出现此处最多的数字基本思想:数组中出现次数大于一半的数字出现的次数一定比其余所有数字出现的次数总和还要大
3.2代码:

#include<iostream>
#include<vector>
using namespace std;

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) 
    {
        if(numbers.empty())
            return 0;
        int data=0,times=1;
        data = numbers[0];
        for(int i=1;i<numbers.size();i++)
        {
            if(times==0)
            {
                times=1;
                data = numbers[i];
                continue;
            }
            if(numbers[i]==data)
                times++;
            else
                times--;
        }

        //检测data是不是出现次数最多的那个数
        times=0;
        for(int i=0;i<numbers.size();i++)
            if(data==numbers[i])
                times++;
        if(times<=(numbers.size()/2))
            data=0;
        return data;
    }
};



int main()
{
    int data[] = {1,2,3,2,2,2,5,4,2};
    vector<int> vec;
    for(int i=0;i<9;i++)
        vec.push_back(data[i]);

    Solution A;
    cout << A.MoreThanHalfNum_Solution(vec) <<endl;

    system("pause");
    return 1;


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值