[Leetcode] 229. Majority Element II 解题报告

本文介绍两种算法:Partition方法与BM投票法,用于找出数组中出现次数超过n/3的元素,强调线性时间和O(1)空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorithm should run in linear time and in O(1) space.

思路

1、Partition方法:可以调用基本快速排序中的partition方法,该方法可以在线性时间内,按照某个数将数组分为两部分,其中左边是比这个数小的数,右边是比这个数大的数。在这个题目中,我们要找到出现次数超过1/3的数,那么这样的数最多有两个,利用partition找出应该出现在数组1/3以及2/3处的值,则出现超过1/3的数必然在这两个数中。然后再验证这两个数是不是解。这种解法期望的时间复杂度是O(nlogn),但是在最坏情况下时间复杂度依然是O(N^2)。Partition方法可以通过Leetcode上面的测试用例,但是耗时非常多。

2、BM(Boyer-Moore Majority Vote Algorithm)投票法:设置一个计数器,在遍历数组的时候,如果是这个数,则计数器加1,否则减1,该方法用来计数超过一半的数非常方便。在这里我们改进一下BM投票计数法:设置两个计数器,如果是两个数中的一个,则对应的计数器加1,如果不是这两个数中的任何一个,则两个计数器都减1。如果计数器为0了,则统计当前这个数。那么如果一个数出现次数超过1/3,则最后必然出现在统计的数中,但是我们不确定得到的这两个数出现次数是否超过1/3,因此最后需要验证一下。该算法的时间复杂度是O(n),空间复杂度是O(1)。

代码

1、Partition方法:

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        if (nums.size() == 0) {
            return {};
        }
        int length = nums.size(), left = 0, right = length - 1;
        int num1 = 0, num2 = 0, pos = 0;
        while ((pos = partition(nums, left, right)) != length / 3) {
            pos < length / 3 ? left = pos + 1 : right = pos - 1;
        }
        num1 = nums[length / 3];
        left = 0, right = length - 1;
        while((pos = partition(nums, left, right)) != length * 2 / 3) {
            pos < length * 2 / 3 ? left = pos + 1 : right = pos - 1;
        }
        num2 = nums[length * 2 / 3];
        int count1 = 0, count2 = 0;
        for (auto val : nums) {
            if (val == num1) {
                ++count1;
            }
            else if (val == num2) {
                ++count2;
            }
        }
        vector<int> ret;
        if (count1 > length / 3) {
            ret.push_back(num1);
        }
        if (count2 > length / 3) {
            ret.push_back(num2);
        }
        return ret;
    }
private:
    int partition(vector<int>& nums, int left, int right) {    
        int val = nums[right];    
        for(int i = left; i < right; ++i) {    
            if(nums[i] < val) {  
                swap(nums[left++], nums[i]);    
            }  
        }  
        swap(nums[right], nums[left]);    
        return left;    
    }
};

2、BM投票法:

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
        if (nums.size() == 0) {
            return {};
        }
        int num1, num2, count1 = 0, count2 = 0;
        for (auto val : nums) {
            if (val == num1) {
                ++count1;
            }
            else if (val == num2) {
                ++count2;
            }
            else if (count1 == 0) {
                ++count1, num1 = val;
            }
            else if (count2 == 0) {
                ++count2, num2 = val;
            }
            else {
                --count1, --count2;
            }
        }
        count1 = 0, count2 = 0;
        for (auto val : nums) {
            if (val == num1) {
                ++count1;
            }
            else if (val == num2) {
                ++count2;
            }
        }
        vector<int> ret;
        if (count1 > nums.size() / 3.0) {
            ret.push_back(num1);
        }
        if (count2 > nums.size() / 3.0) {
            ret.push_back(num2);
        }
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值