c++实现---数组中出现超过一半的数字

题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
题目抽象:给定一个数组,找出数组中的众数,若有,返回众数,若没有,返回0
众数定义:数组中出现次数大于数组一般的元素
前两种方法最容易实现,笔试或面试可以先做出来,然后根据面试要求不断优化
方法一:哈希法
map/unordered_map原理和使用整理: https://blog.csdn.net/Blues1021/article/details/45054159?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
根据题目意思,显然可以先遍历一遍数组,在map中存每个元素出现的次数,然后再遍历一次数组,找出众数。
代码

#include<unordered_map>
class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if(numbers.size()<=0){//异常处理
            return 0;
        }
        unordered_map<int,int> map;
        for(const int val:numbers) ++map[val];//统计每个元素出现次数
        for(const int val:numbers){
            if(map[val]>numbers.size()/2){//遍历找到val次数大于n/2的就是要找的那个众数
                return val;
            }
        }
        return 0;
    }
};

时间复杂度:O(n)
空间复杂度:O(n)
方法二:排序法
可以先将数组排序,然后可能的众数肯定在数组中间,然后判断一下。
代码

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if(numbers.size()<=0){//异常处理
            return 0;
        }
        sort(numbers.begin(),numbers.end());//对数组排序
        int cond=numbers[numbers.size()/2];//取排序好数组的中间元素
        int cnt=0;
        for(const int k:numbers){
            if(cond==k) ++cnt;//统计该元素出现的次数
        }
        if(cnt>numbers.size()/2) return cond;
        return 0;
    }
};

时间复杂度:O(nlongn)
空间复杂度:O(1)

如果时间复杂度要求为O(n),考虑下面的方法
方法三:基于Partiotion函数,但是这种方法会改变数组,时间复杂度为O(N)

class Solution {
public:
    bool checkHalf(vector<int> num,int length,int tar){
        int count=0;
        for(int i=0;i<length;++i){
            if(num[i]==tar){
                count++;
            }
        }
        bool isMoreHalf=true;
        if(2*count<=length){//次数最多的数的个数必须大于数组长度的一半
            isMoreHalf=false;
        }
        return isMoreHalf;
    }
    int Partition(vector<int> &num,int left,int right){//快速排序的基础,选定一个数,实现在数组中比它小的数在它左边,比它大的数在它右边
        int pivot=num[right];
        int small=left-1;
        for(int j=left;j<right;++j){
            if(num[j]<=pivot){//将小于pivot的数向前交换
                ++small;
                swap(num[small], num[j]);
            }
        }
        swap(num[small+1],num[right]);
        return small+1;
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if(numbers.size()<=0){//异常处理
            return 0;
        }
        int left=0,right=numbers.size()-1;
        int index=Partition(numbers,left,right);
        int mid=numbers.size()>>1;
        while(index!=mid){//如果选定的数下标刚好是数组一半,则这个数就是数组的中位数
            if(index>mid){//下标大于n/2,中位数应该在他的左边
                right=index-1;
                index=Partition(numbers,left,right);
            }else{//下标小于n/2,中位数应该在他的右边
                left=index+1;
                index=Partition(numbers,left,right);
            }
        }
        int result=numbers[mid];
        if(!checkHalf(numbers,numbers.size(),result)){
            result=0;
        }
        return result;
    
    }
};

方法四:基于数组特点,这种方法不改变数组结构,时间复杂度为O(N)
遍历数组的时候存储两个值,一个是数组中的数,一个是次数,当我们遍历到下一个数字的时候,如果和之前保存的数字相同,次数加1,如果不同次数减1,如果次数为0,则保存下一个数字,并把次数设为1,由于要找的数字比其他所有数字出现的次数之和还要多,因此最后以此次数设为1的数字就是目标。

class Solution {
public:
    bool checkHalf(vector<int> num,int length,int tar){
        int count=0;
        for(int i=0;i<length;++i){
            if(num[i]==tar){
                count++;
            }
        }
        bool isMoreHalf=true;
        if(2*count<=length){//次数最多的数的个数必须大于数组长度的一半
            isMoreHalf=false;
        }
        return isMoreHalf;
    }
    int Partition(vector<int> &num,int left,int right){//快速排序的基础,选定一个数,实现在数组中比它小的数在它左边,比它大的数在它右边
        int pivot=num[right];
        int small=left-1;
        for(int j=left;j<right;++j){
            if(num[j]<=pivot){//将小于pivot的数向前交换
                ++small;
                swap(num[small], num[j]);
            }
        }
        swap(num[small+1],num[right]);
        return small+1;
    }
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if(numbers.size()<=0){//异常处理
            return 0;
        }
        int result=numbers[0];
        int times=1;
        for(int i=1;i<numbers.size();++i){
            if(times==0){
                result=numbers[i];
                times=1;
            }else if(numbers[i]==result){
                ++times;
            }else{
                --times;
            }
        }
        if(!checkHalf(numbers,numbers.size(),result)){
            result=0;
        }
        return result;
    
    }
};

猜你喜欢

转载自blog.csdn.net/Fizz6018/article/details/107015251