查找主元素

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

空间复杂度O(n)可用哈希,简单的就不给了。仅给出时间复杂度O(n),空间复杂度O(1)的算法。

采用快速排序中的分割思想


int parti(vector<int> &nums, int p, int r, int tar)
    {
        int k = p;
        for( int i = p; i <= r; ++i )
        {
            if( nums[i] <= tar ) swap(nums[i], nums[k++]);
        }
        return k;
    }
    int majorityNumber(vector<int> nums) {
        // write your code here
        if( nums.size() <= 2 ) return nums[0];
        int cur = nums[0], p = 0, r = nums.size()-1;
        int k = parti(nums, p, r, cur);
        while( k <= nums.size()/2 )
        {
            cur = nums[k];
            for( int i = k+1; i <= r; ++i ) cur = min(cur, nums[i]);
            k = parti(nums, k, r, cur);
            if( k > nums.size()/2 ) return cur;
        }
        while( k > nums.size()/2 )
        {
            int last = cur;
            cur = INT_MIN;
            for( int i = p; i < k; ++i )
            {
                if( nums[i] < last ) cur = max(cur, nums[i]);
            }
            if( cur == last ) return cur;
            k = parti(nums, p, k-1, cur);
            if( k <= nums.size()/2 ) return last;
        }
    }


其实还有更简单的算法,每次“删掉”两个不同元素,懒得写了。下面的变式就是采用这种思想,因此上面一题的更简算法可仿下

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

算法思想是每次 “删除” 3个不同元素,最后剩下的元素就是候选主元素,重新遍历一次数组计算候选主元素的出现次数即可


class Solution {
public:
    /**
     * @param nums: A list of integers
     * @return: The majority number occurs more than 1/3.
     */
    int majorityNumber(vector<int> nums) {
        // write your code here
        int repeat[3] = {0,0,0};
        int mainElement[3];
        for( int i = 0; i < nums.size(); ++i )
        {
            int j = -1, emptyIdx = -1;
            while( ++j < 3 )
            {
                if( repeat[j] != 0 && mainElement[j] == nums[i] )
                {
                    ++repeat[j];
                    break;
                }
                else if( repeat[j] == 0 && emptyIdx < 0 ) emptyIdx = j;
            }
            //fill empty mainElement
            if( j == 3 )
            {
                repeat[emptyIdx] = 1;
                mainElement[emptyIdx] = nums[i];
                if( repeat[0] && repeat[1] && repeat[2] )
                {
                    --repeat[0];
                    --repeat[1];
                    --repeat[2];
                }
            }
        }
        
        for( int i = 0; i < nums.size(); ++i )
        {
            if( repeat[0] && mainElement[0] == nums[i] )
            {
                ++repeat[0];
                if( repeat[0] > nums.size()/3 ) return mainElement[0];
            }
            else if( repeat[1] && mainElement[1] == nums[i] )
            {
                ++repeat[1];
                if( repeat[1] > nums.size()/3 ) return mainElement[1];
            }
        }
        return mainElement[2];
    }
};


对于更一般的变式

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


class Solution {
public:
    /**
     * @param nums: A list of integers
     * @param k: As described
     * @return: The majority number
     */
    int majorityNumber(vector<int> nums, int k) {
        // write your code here
        int *repeat = new int[k];
        int *mainElement = new int[k];
        memset(repeat, 0, k*sizeof(int));
        
        for( int i = 0; i < nums.size(); ++i )
        {
            int j = -1, emptyIdx = -1;
            while( ++j < k )
            {
                if( repeat[j] > 0 && mainElement[j] == nums[i] )
                {
                    ++repeat[j];
                    break;
                }
                else if( repeat[j] == 0 && emptyIdx < 0 ) emptyIdx = j;
            }
            //fill the empty slot
            if( j == k )
            {
                repeat[emptyIdx] = 1;
                mainElement[emptyIdx] = nums[i];
                bool isFull = true;
                for( int t = 0; t < k; ++t )
                {
                    if( repeat[t] == 0 ){ isFull = false; break; }
                }
                if( isFull )
                {
                    for( int t = 0; t < k; ++t ) --repeat[t];
                }
            }
        }
        
        unordered_map<int, int> candidate;
        for( int i = 0; i < k; ++i ) if( repeat[i] > 0 )
        { 
            candidate[mainElement[i]] = 0; 
        }
        
        for( int i = 0; i < nums.size(); ++i )
        {
            if( candidate.find(nums[i]) != candidate.end() )
            {
                ++candidate[nums[i]];
                if( candidate[nums[i]] > nums.size() / k )
                    return nums[i];
            }
        }
        
    }
};


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值