lintcode(5)——主元素

本文介绍了一种在数组中寻找主元素的算法,主元素是指在数组中出现次数超过一定比例的元素,如超过一半、三分之一或1/k。文章提供了三种不同情况下的解决方案,包括使用中位数、抵消算法和改进的抵消算法。这些方法均能在特定的时间和空间复杂度下找到主元素。

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

46. 主元素

给定一个整型数组,找出主元素,它在数组中的出现次数严格大于数组元素个数的二分之一。

样例 1:

输入: [1, 1, 1, 1, 2, 2, 2]
输出: 1

样例 2:

输入: [1, 1, 1, 2, 2, 2, 2]
输出: 2

挑战

要求时间复杂度为O(n),空间复杂度为O(1)

注意事项

你可以假设数组非空,且数组中总是存在主元素。

 

方法一:

求中位数,主元素肯定是中位数,否则该元素数量少于n/2则不是主元素;快速排序,然后确定中位数。时间复杂度O(nlogn)

class Solution {
public:
    int majorityNumber(vector<int> &nums) {
        // write your code here
        sort(nums.begin(),nums.end());
        int len=nums.size();
        return nums[len/2];
    }
};

方法二:

思路比较新颖,原理是如果一个元素中存在一个主元素(个数大于n/2),则同时删除两个不相等的数,这个主元素不会改变。

简单的说就是一个大小为n的数组中存在一个元素的个数大余n/2,则如果用这个数组中其他的数和该主元素进行抵消的话,最后剩下的一定是主元素,因为主元素个数最多。

该方法可以在O(n)时间内找到主元素。十分高效。

class Solution {
public:
    int majorityNumber(vector<int> &nums) {
        // write your code here
        if (nums.size() == 0) {
            return -1;
        }
        int count = 0;
        int major = nums[0];
        //取出主元素
        for (int i = 0; i < nums.size(); i++) {
            if (major == nums[i]) {
                count++;
            } else {
                count--;
            }
            if (count == 0) {
                major = nums[i];
                count++;
            }
        }
        //判断取出的主元素是不是主元素
        count = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (major == nums[i]) {
                count++;
            }
        }
        if (count > nums.size() / 2) {
            return major;
        }
        return -1;
    }
};

47. 主元素 II

给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的三分之一。

样例

例1:

输入: [99,2,99,2,99,3,3], 
输出: 99.

例2:

输入: [1, 2, 1, 2, 1, 3, 3], 
输出: 1.

挑战

要求时间复杂度为O(n),空间复杂度为O(1)。

注意事项

数组中只有唯一的主元素

方法一:以空间换时间(将数组中的元素作为新建数组的下标,新建数组用于存储各元素出现的次数) 

class Solution {
public:
    int majorityNumber(vector<int> &nums) {
        // write your code here
        int i,len=nums.size(),max=nums[0];
        for(i=1;i<len;i++)
        {
            if(max<nums[i]) max=nums[i];
        }
        int temp[max+1]={0};
        if(len== 0)
            return 0;
        for(i = 0;i< len;i++){
            temp[nums[i]]++;
        }
        for(i=0;i<max+1;i++)
        {
            if(temp[i]>len/3)
            {
                return i;
            }
        }
        return 0;
    }
};

方法二:如果出现3个不一样的数,就抵消掉。记录两个value和每个value分别的出现次数。如果遍历到的数和两个value都不等,就count都减1。最后可能会剩下两个value,再遍历一次整个数组验证一下谁是主元素。

class Solution {
public:
    int majorityNumber(vector<int> &nums) {
        // write your code here
        int a = nums[0], cnta = 0;  //我用a b分别表示两个不一样的数
        int b = nums[0], cntb = 0;
        int i;
        for(i=0;i<nums.size();i++)
        {
            if(nums[i]==a)
            {
                cnta++;
                continue;
            }
            if(nums[i]==b)
            {
                cntb++;
                continue;
            }
            if(cnta==0)
            {
                a=nums[i];
                cnta++;
                continue;
            }
            if(cntb==0)
            {
                b=nums[i];
                cntb++;
                continue;
            }
            cnta--;
            cntb--;
        }
        cnta = 0;
        cntb = 0;

        for (i=0;i<nums.size();i++)
        {
            if (nums[i] == a) {
                cnta++;
            } 
            else if (nums[i]== b)
            {
                cntb++;
            }
        }
        
        if (cnta > nums.size() / 3) {
            return a;
        }
        if (cntb > nums.size() / 3) {
            return b;
        }

48. 主元素 III

给定一个整型数组,找到主元素,它在数组中的出现次数严格大于数组元素个数的1/k

样例

例1:

输入: [3,1,2,3,2,3,3,4,4,4] and k=3, 
输出: 3.

例2:

输入: [1,1,2] and k=3, 
输出: 1.

挑战

要求时间复杂度为O(n),空间复杂度为O(k)

注意事项

数组中只有唯一的主元素

class Solution {
public:
     int majorityNumber(vector<int> &nums, int k) {
        // write your code here
        int i,len=nums.size(),max=nums[0];
        for(i=1;i<len;i++)
        {
            if(max<nums[i]) max=nums[i];
        }
        int temp[max+1]={0};
        if(len== 0)
            return 0;
        for(i = 0;i< len;i++){
            temp[nums[i]]++;
        }
        for(i=0;i<max+1;i++)
        {
            if(temp[i]>len/k)
            {
                return i;
            }
        }
        return 0;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值