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

题目描述:

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/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

解析思路1:哈希表统计

  • 官方思路-哈希表.

  • 可以用哈希表来快速统计每个元素出现的次数。使用哈希映射(HashMap)来存储每个元素以及出现的次数。对于哈希映射中的每个键值对,键表示一个元素,值表示该元素出现的次数。

代码(python3)


class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        counts = collections.Counter(nums)
        return max(counts.keys(), key=counts.get)

代码(cpp)

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        unordered_map<int, int> count; // 创建哈希表
        int majority = 0, res = 0;     // 声明变量
        for (int num: nums) {  // 循环遍历数组 nums 并将数组中的每个元素加入哈希映射中
            ++count[num];
            if (count[num] > res) { // 遍历哈希映射中的所有键值对
                majority = num;
                res = count[num];
            }
        }
        return majority; // 返回值最大的键
    }
};


  • 或者
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        unordered_map <int,int> map;
        for(int n:nums)   
            if(++ map[n] > nums.size()/2)  
            	return n;         
        return -1;
    }
};

复杂度分析:

  • 时间复杂度:O(n),其中 n 是数组 nums 的长度。我们遍历数组 nums 一次,对于 nums 中的每一个元素,将其插入哈希表都只需要常数时间。
  • 空间复杂度:O(n)。

解析思路2:排序

  • 官方思路-排序.

  • 若将数组 nums 中的所有元素按照单调递增或单调递减的顺序排序,那么下标为 ⌊ n/2⌋ 的元素(下标从 0 开始)一定是众数。

  • 算法流程示意图:

  • 奇数与偶数的排序情况:

在这里插入图片描述

  • 不管对于哪种情况,数组下面的线表示如果众数是数组中的最小值时覆盖的下标,数组下面的线表示如果众数是数组中的最大值时覆盖的下标。对于其他的情况,这条线会在这两种极端情况的中间。对于这两种极端情况,它们会在下标为(n/2)的地方有重叠。因此,无论众数是多少,返回下标(n/2)对应的值都是正确的。

代码(python3)

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        nums.sort()
        res = nums[len(nums) // 2]
        return res
        #return nums[len(nums) // 2
        

代码(cpp)


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


复杂度分析:

  • 时间复杂度:O(nlogn)。将数组排序的时间复杂度为 O(nlogn)。
  • 空间复杂度:O(logn)。如果使用语言自带的排序算法,需要使用 O(logn) 的栈空间。如果自己编写堆排序,则只需要使用 O(1) 的额外空间。

解析思路3: Moore投票

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

代码(python3)


class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        count = 0
        candidate = None

        for num in nums:
            if count == 0:
                candidate = num
            count += (1 if num == candidate else -1)
        return candidate

  • 或者
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        votes = 0
        for num in nums:
            if votes == 0: x = num
            votes += 1 if num == x else -1
        return x

代码(cpp)


class Solution {
public:
    int majorityElement(vector<int>& nums) {    
//摩尔投票法,投目标值++,不投--,超过一半以上的人投,出结果啦
        int count = 0, candidate = 0;
        for(int n : nums)
        {
            if(count == 0)        candidate = n;

            if(n == candidate)    count++;
            else                  count--;
        }
        return candidate;
    }
};

  • 或者
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int x = 0, votes = 0;
        for(int num : nums){
            if(votes == 0) x = num;
            votes += num == x ? 1 : -1;
        }
        return x;
    }
};


  • 复杂度分析:

  • 时间复杂度:O(n)。Moore 算法只对数组进行了一次遍历。

  • 空间复杂度:O(1)。Moore 算法只需要常数级别的额外空间。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值