169 求众数 哈希 分治 投票

博客介绍了在数组中寻找众数的问题,提供了多种解决方案,包括哈希方法(时间复杂度O(n),空间复杂度O(n))、排序(时间复杂度O(nlgn),空间复杂度O(1)或O(n))、随机化策略(时间复杂度O(∞),空间复杂度O(n))、分治法以及Boywer-Moore投票算法(时间复杂度O(n),空间复杂度O(1))。内容详细阐述了每种方法的思路和实现代码。
摘要由CSDN通过智能技术生成

题目 题解
题目描述:给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在众数。

哈希:

时间复杂度:O(n)
空间复杂度:O(n)

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        dic = {}
        l=0   #长度,反正后面也要循环,多占用一个变量的空间省去len()的时间
        for n in nums:
            l+=1
            if n in dic:
                dic[n]+=1
            else:
                dic[n]=1
        for key in dic.keys():
            if dic[key]/l>=0.5:
                return key
# 官方的哈希就是不一样
# 不熟的点:counter,带key的max()
def majorityElement(self, nums: List[int]) -> int:
        counts = collections.Counter(nums)
        return max(counts.keys(), key=counts.get)

cpp:

 int majorityElement(vector<int>& nums) {
        map<int,int> mp;
        for(int i=0;i<nums.size();i++)
        {
            mp[nums[i]]++;
            if(mp[nums[i]]>nums.size()/2)
                return nums[i];
        }
        return -1;
    }

排序:

时间复杂度:O(nlgn)
空间复杂度:O(1) 或者 O(n)
我真的是越来越懒了哈哈

def majorityElement(self, nums):
        nums.sort()
        return nums[len(nums)//2]

随机化

随机选一个数,然后算它出现的次数是否大于一半。

时间复杂度:O(∞)
空间复杂度:O(n)

def majorityElement(self, nums):
        majority_count = len(nums)//2
        while True:
            candidate = random.choice(nums)
            if sum(1 for elem in nums if elem == candidate) > majority_count:
                return candidate

分治

劝退过我的分治qwq
采用的经典分治法,分成好多个子问题(一直2分到只剩1项),子问题能够轻松得到结果,然后溯回,若区间大于1,判断左右众数相当与否,若不等需要将整个区间遍历一遍寻找真确的众数,若没有众数,返回右边的值,然后往上推,最终就能得到正确的众数。
在这里插入图片描述
在这里插入

def majorityElement(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        def majority_element_rec(lo, hi):
            # base case; the only element in an array of size 1 is the majority
            # element.
            if lo == hi:
                return nums[lo]

            # recurse on left and right halves of this slice.
            mid = (hi-lo)//2 + lo
            left = majority_element_rec(lo, mid)
            right = majority_element_rec(mid+1, hi)

            # if the two halves agree on the majority element, return it.
            if left == right:
                return left

            # otherwise, count each element and return the "winner".
            left_count = sum(1 for i in range(lo, hi+1) if nums[i] == left)
            right_count = sum(1 for i in range(lo, hi+1) if nums[i] == right)

            return left if left_count > right_count else right

        return majority_element_rec(0, len(nums)-1)

cpp:

class Solution {
public:
   int majorityElement(vector<int>& nums) {
        return majorityElement(nums, 0, nums.size() - 1);
    }

    int majorityElement(vector<int>& nums, int lptr, int rptr) {
        if(lptr == rptr) return nums[lptr];

        int mid = (lptr + rptr) / 2;
        int left = majorityElement(nums, lptr, mid);
        int right = majorityElement(nums, mid + 1, rptr);

        if(left == right) return left;

        int leftCount = 0;
        int rightCount = 0;
        for(int i = lptr; i < mid; i++) if(left == nums[i]) leftCount++;
        for(int i = mid; i < rptr; i++) if(right == nums[i]) rightCount++;
        return leftCount > rightCount ? left : right;
    }
};

Boyer-Moore 投票算法

我们把众数记为 +1,把其他数记为 −1 ,将它们全部加起来,显然和大于 0 ,从结果本身我们可以看出众数比其他数多。
  本质上, Boyer-Moore 算法就是找 nums 的一个后缀 suf ,其中 suf[0] 就是后缀中的众数。我们维护一个计数器,如果遇到一个我们目前的候选众数,就将计数器加一,否则减一。只要计数器等于 0 ,我们就将 nums 中之前访问的数字全部 忘记 ,并把下一个数字当做候选的众数。最后,总有一个后缀满足计数器是大于 0 的,此时这个后缀的众数就是整个数组的众数。
  我们的候选者并不是真正的众数,但是我们在 遗忘 前面的数字的时候,要去掉相同数目的众数和非众数(如果遗忘更多的非众数,会导致计数器变成负数)。
Python:

def majorityElement(self, nums):
        count = 0
        candidate = None

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

        return candidate

C++:

int majorityElement(vector<int>& nums) {
        int count=0;
        int candicate;
        for(int item:nums)
        {
            if(count==0)
                candicate = item;
            item==candicate ? count++ : count--;
        }
        return candicate;
    }

复杂度分析
时间复杂度:O(n)
Boyer-Moore 算法严格执行了 n 次循环,所以时间复杂度是线性时间的。
空间复杂度:O(1)
Boyer-Moore 只需要常数级别的额外空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值