• 【LeetCode】【剑指offer】【数组中出现次数超出一半的数字】


    剑指 Offer 39. 数组中出现次数超过一半的数字

     

    数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

    你可以假设数组是非空的,并且给定的数组总是存在多数元素。

    示例 1:

    输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
    输出: 2
     

    限制:

    1 <= 数组长度 <= 50000

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

    你可以假设数组是非空的,并且给定的数组总是存在多数元素。

    示例 1:

    输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
    输出: 2
     

    限制:

    1 <= 数组长度 <= 50000

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    我们可以采用map也就是键值对的形式,存储每个出现的数据的出现次数,同时我们需要记录当前的数据的出现次数是不是已经比之前的最大的出现次数大了,如果是的话,就更新之前的出现的最大次数,同时记录下,这是哪一个数据出现的次数这么多。

    并且根据题目的描述,一定会有一个数字的出现次数超过数组长度的一半,也就是说只要将那个出现次数最多的数字返回即可。或者还没有将数组全部读取完就已经有某一个数据的出现次数是全部数组的出现次数的一半了,就可以直接返回当前这个数了,不用再继续向后遍历了。

    一、哈希表 

    1. class Solution {
    2. public:
    3. int majorityElement(vector<int>& nums) {
    4. map<int ,int> m;
    5. int max_count=0;
    6. int max=0;
    7. for(auto ch:nums)
    8. {
    9. m[ch]++;
    10. if(m[ch]>max_count)
    11. {
    12. max=ch;
    13. max_count=m[ch];
    14. }
    15. if(max_count>=nums.size())
    16. {
    17. return max;
    18. }
    19. }
    20. return max;
    21. }
    22. };

    二、排序

    因为我们所要寻找的数据超出了数组的一半的数据,所以我们可以将数据排序,然后中间的数据一定就是我们所要寻找的出现次数超出数组长度一半的数据。

      

    1. class Solution {
    2. public:
    3. int majorityElement(vector<int>& nums) {
    4. sort(nums.begin(),nums.end());
    5. return nums[nums.size()/2];
    6. }
    7. };

     三、摩尔投票法

    如果存在出现次数大于数组的总长度的一半的数据,那么即使将这个数组任意对半分,一定在其中一半的数据中这个出现的次数超出了一半。(反证法,如果这个数据的出现的次数在两半中均没有到一半,那么这两半加载一起,这个数据也的出现次数也不可能超出总的数据个数的一半)

    所以我们首先指定一个数据,并且统计这个数据的出现次数。顺序遍历,如果是这个数据,count就++,如果不是这个数据,count就--,当count<0的时候,就说明当前这个数据在我们之前的数据中没有占到一半,也就是说在前面一半中不是那个众数。所以接下来我们就可以重新指定我们的假设的数据,继续在后半部分的数据集合中遍历。根据我们之前的理论,如果那个出现次数超出数据个数一半的数字,在这个数据的前半中出现的次数没有超过一半,那么它在这个数据集中后半的出现次数一定会超过一半。

    从而我们就能够找到我们想要返回的数字了。

    1. class Solution {
    2. public:
    3. int majorityElement(vector<int>& nums) {
    4. int ticket=-1;
    5. int count=0;
    6. for(auto num:nums)
    7. {
    8. if(num==ticket)
    9. {
    10. count++;
    11. }
    12. else if(--count<0)
    13. {
    14. ticket=num;
    15. count=1;
    16. }
    17. }
    18. return ticket;
    19. }
    20. };

    四、同时去掉两个不同的数字

    目标数据超过数组长度的一半,那么对数组,我们同时去掉两个不同的数字,到最后剩下的一个数就是该数字。如果剩下两个,那么这两个也是一样的,就是结果),在其基础上把最后剩下的一个数字或者两个回到原来数组中,
    将数组遍历一遍统计一下数字出现次数进行最终判断。

    1. class Solution {
    2. public:
    3. int majorityElement(vector<int>& nums) {
    4. if(nums.size() == 0){
    5. return 0;
    6. }
    7. //可以采取不同的数量进行抵消的思路
    8. int number = nums[0];
    9. int times = 1;
    10. for(int i = 1; i < nums.size(); i++){
    11. if(times == 0){ //如果当前times是0,说明之前的不同抵消完了
    12. number = nums[i];
    13. times = 1;
    14. } else if(nums[i] == number){
    15. times++;
    16. } else{
    17. times--;
    18. }
    19. } //如果输入本身满足条件,则times一定>0, 并且number保存的就是准目标,但是还需要确认
    20. int count = 0;
    21. for(int i = 0; i < nums.size(); i++){
    22. if(nums[i] == number){
    23. count++;
    24. }
    25. }
    26. return count > nums.size()/2 ? number : 0;
    27. }
    28. };

     

  • 相关阅读:
    DINO目标检测实验结果可视化(1)——loss和mAP
    Webpack 打包 commonjs 和 esmodule 动态引入模块的产物对比
    算法分析与设计CH15:动态规划算法详解合集——装配线问题、矩阵链乘、LCS(最长公共子序列问题)、最大子数组和问题
    基于Python实现的神经网络分类MNIST数据集
    Databricks 入门之sql(二)常用函数
    Java多线程(四)锁策略(CAS,死锁)和多线程对集合类的使用
    “讳疾忌医”的开源走不远
    uniapp+vue基于Android的图书馆借阅系统qb4y3-nodejs-php-pyton
    【元宇宙欧米说】MetaArks:打造社交+游戏的商业发展模式
    HTML5期末考核大作业 基于HTML+CSS+JavaScript沪上美食(9页)
  • 原文地址:https://blog.csdn.net/weixin_62684026/article/details/126411462