牛客JZ39-数组中出现次数超过一半的数字

问题描述

给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
数据范围:n≤50000,数组中每个数的值:0≤val≤10000
要求:时间复杂度: O ( 1 ) O(1) O1,空间复杂度: O ( n ) O(n) On

题目链接: https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&tqId=11181&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

示例

示例1
输入:[1,2,3,2,2,2,5,4,2]
返回值:2

示例2
输入:[3,3,3,3,2,2,2]
返回值:3

示例3
输入:[1]
返回值:1

具体思路

思路一

  定义unordered_map,使用<数字,次数>的映射关系,最后统计每个字符出现的次数。
   首先定义一个unordered_map<int,int>。然后计算出一半数组的大小,接着遍历整个数组,如果unordered_map中已经有该数就自增,否则就新插入,次数设为1。最后判断map中值出现最多次的是否大于整个数组长度的一半,是就返回数值,否则返回0。

思路二

  排序,出现次数最多的数字,一定在中间位置。然后检测中间出现的数字出现的次数是否符合要求。
   首先对整个数组进行排序,然后计算中间数组的值,接着遍历整个数组,对目标值进行次数的统计,最后判断目标值出现的次数是否大于数组长度的一半,是则返回数值,否则返回0.

思路三

  目标条件:目标数据超过数组长度的一半,那么对数组,我们同时去掉两个不同的数字,到最后剩下的一个数就是该数字。(如果剩下两个,那么这两个也是一样的,就是结果),在其基础上把最后剩下的一个数字或者两个回到原来数组中,将数组遍历一遍统计一下数字出现次数进行最后判断。
  首先需要考虑数组是否为空的情况,然后对数组从前往后进行抵消,如果相同,计数就+1,不同计数就-1,接着计算最后剩下的数字在整个数组中出现的次数,最后判断这个数出现的次数是否大于数组长度的一半,是就返回数值,否则返回0。

代码实现

思路一

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型vector 
     * @return int整型
     */
    int MoreThanHalfNum_Solution(vector<int>& numbers) {
        // write code here
        int half=numbers.size()/2;  //计算数组一半的长度

        unordered_map<int,int> _map;
        for(int i=0;i<numbers.size();i++)
        {
            auto it=_map.find(numbers[i]);   //如果已经在unordered_map中,进行自增,如果不在,首次出现,插入
            if(it==_map.end())  
            {
                //_map.insert(make_pair(numbers[i],1)); //make_pair不需要指定模板类型,可以通过值生成pair对象
               //_map.insert(pair<int,int>(numbers[i],1)); //pair可以将两个类型的数据封装到一个对象中
              // _map.insert(pair(numbers[i],1));
               //_map.insert({numbers[i],1});
            }
            else
            {
                 _map[numbers[i]]++;
            }

			//自增或者插入一个,直接进行判定。注意,这里要考虑测试用例为{1}的情况
			//走到这里,对应的key val一定存在
            if(_map[numbers[i]]>half)  
            {
                return numbers[i];
            }
        }
        //走到这里,说明没有找到
        return 0;
    } 
};

思路二

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型vector 
     * @return int整型
     */
    int MoreThanHalfNum_Solution(vector<int>& numbers) {
    // write code here
    
    sort(numbers.begin(),numbers.end()); //默认为升序,即第三个参数为less<int>()
   //sort(numbers.begin(),numbers.end(),greater<int>());  //如果想要降序则需要传greater<int>()
    int target=numbers[numbers.size()/2];    //排序后出中间的数一定是出现次数最多的
    int count=0;

    for(int i=0;i<numbers.size();i++)  //遍历整个数组,统计中间数的次数
    {
        if(target==numbers[i])
        {
            count++;
        }
    }

    if(count>numbers.size()/2)  //如果中间数的次数大于数组的一半就返回
    {
        return target;
    }

    return 0;

    }
};

思路三

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param numbers int整型vector
     * @return int整型
     */
    int MoreThanHalfNum_Solution(vector<int>& numbers) {
        // write code here
        
        if(numbers.size()==0)
        {
            return 0;
        }
		
		//采用不用的数量进行抵消的思路
        int number=numbers[0];
        int times=1;
        for(int i=1;i<numbers.size();i++)
        {
            if(times==0) //如果当前times是0,说明之前的不同数已经抵消完了
            {
                number=numbers[i];
                times=1;
            }
            else if(number==numbers[i])
            {
                times++;
            }
            else
            {
                times--;
            }
        }

		//如果输入本身满足条件,则times一定>0,并且number保存的就是准目标,但是还需要确认一下
        int count=0;
        for(int i=0;i<numbers.size();i++)  //遍历数组统计出现的次数
        {
            if(number==numbers[i])
            {
              count++;
            }
        }

        if(count>numbers.size()/2)  //如果中间数的次数大于数组的一半就返回
        {
           return number;
        }
        else 
        {
             return 0;
        }
    }
};

  • 24
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值