Leetcode Majority Element I&II

本篇讲述Leetcode里面两个关于找出出现次数最多元素的相似题目,通过多种解法,展现摩尔投票法的魅力。

leetcode #169 Majority Element
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.
翻译为中文:给定一个大小为n的数组,从中找出出现次数大于n/2的元素。假设数组是非空的,并且一定存在次数大于n/2的元素。

  • 摩尔投票法
    摩尔投票法的基本思想很简单,在每一轮投票过程中,从数组中找出一对不同的元素,将其从数组中删除。这样不断的删除直到无法再进行投票,如果数组为空,则没有任何元素出现的次数超过该数组长度的一半。如果只存在一种元素,那么这个元素则可能为目标元素。本题已经假定一定存在次数大于n/2的元素,那么可知这样的元素只有一个。
class Solution{
public:
    int majorityElement(vector<int>& nums) {

        int ans, cnt = 0;

        for(int n: nums){

            if (cnt == 0 || n == ans){
                cnt++; ans = n;
            }
            else
                cnt--;
        }
        return ans;
    }
};

需要注意的是,此种解法是建立在一定存在次数大于n/2的元素这一假定上的。如果离开了这个假定,代码这样写是错的,还需要调整。

  • 使用map
#include<iostream>
#include <vector>
#include <map>
#include <utility>
using namespace std;

int majorityElement(vector<int>& nums) {
    map<int,int> temp;
    int len=nums.size();
    int result;
    if(len==1)
    {
        result=nums[0];
        return result;
    }
    for(int i=0;i<len;i++)
    {
        if(temp.count(nums[i])==0)
        {
            temp.insert(make_pair(nums[i],1));
        }
        else
        {
            temp[nums[i]]++;
        }
    }
    pair<int,int>max_num(temp.begin()->first,temp.begin()->second);
    for(map<int,int>::iterator i=temp.begin();i!=temp.end();i++)
    {
        if(i->second>max_num.second)
        {
            max_num.first=i->first;
            max_num.second=i->second;
        }
    }
    result=max_num.first;
    return result;
}
int main()
{
    vector<int> vec;
    vec.push_back(2),vec.push_back(2);
    cout<<majorityElement(vec)<<endl;
}

这个程序实现的思路很直接,没有摩尔投票法那么有技巧。而且选出的是次数最多的一个,并没有局限在一定有次数大于n/2这个假定上。当所有元素都只出现一次时,返回的是第一个元素,一些说明性的文字在代码中省略了。

  • 普通数组
#include<iostream>
using namespace std;
void majorityelement(int *,int );
void main(){
    int size;
    cout << "input size : " << endl;
    cin >> size;
    int *ar = new int[size]; 
    cout << "input members : " << endl;
    for (int i = 0; i < size; i++){                       //输入数组数据
        cin >> ar[i];
    }
    majorityelement(ar, size);                           //调用功能函数
    cin.get();
    delete[]ar;                                          //销毁从堆中申请的数组内存
}

void majorityelement(int *c,int ssize){
    int * d  = new int[ssize];                       //d矩阵为记录次数的矩阵
    for (int i = 0; i < ssize; i++){
         d[i]=1;
    }
//计算每个元素出现次数(比如矩阵[2 4 5 4 4 2]记录次数为[2 3 1 2 1 1],只用看2,4,5第一次出现次数)
    for (int i = 0; i < ssize-1; i++){
        for (int j = i + 1; j < ssize; j++){
            if (c[i] == c[j]){ 
                d[i]++;
            }
        }
    }
    int maxTimes = d[0];
    int pos=0;
    for (int i = 1; i < ssize; i++){                   //将次数最多的元素的次数排在最前面
        if(maxTimes<d[i]){
            maxTimes=d[i];
            pos=i;
        }
    }
    if (d[0] <= ssize / 2) {                               //测试最大次数是否过半
            delete[] d;
            cout << "Sorry,没有次数过半的元素";
    }
    else{
            delete[] d;
            cout << "次数过半的元素是 :" << endl <<c[pos];
        }
}

这个算法的思路是很简单暴力的。主要是计算每个元素的“伪次数”(不是严格上的每个元素的次数),并且把次数最高的排在数组最前面。计算次数时用了双重for循环(虽然每次内循环时元素变少),这导致此代码效率不高。代码没有局限在一定存在n/2这个假定上。

讲到摩尔投票法,还有一个题目可以show一下,通过这个题目可以充分体现它的巧妙。

leetcode #229 Majority Element II
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.

Hint:
How many majority elements could it possibly have?

题目的意思是找出数组中次数超过1/3的元素。要求在线性时间和o(1)空间复杂度完成。

使用和上题相似思路,将每三个不同的元素删去,超过n/3次数的(如果有的话)就在最后剩下里面。

class Solution {
public:
    vector<int> majorityElement(vector<int>& nums) {
       int cnt1=0,cnt2=0,a=0,b=0;
       for(int i:nums){
             if(i==a)
                 ++cnt1;
             else if(i==b)
                 ++cnt2;
             else if(cnt1==0){
                 a=i;
                 ++cnt1;
             }
             else if(cnt2==0){
                 b=i;
                 ++cnt2;
             }
             else{
                 --cnt1;
                 --cnt2;
             }
       }
       cnt1=cnt2=0;
       for(int i:nums){
           if(i==a) 
                ++cnt1;
           else if(i==b) 
                ++cnt2;
       }
       vector<int> result;
       if(cnt1>nums.size()/3) result.push_back(a);
       if(cnt2>nums.size()/3) result.push_back(b);
       return result;
   }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值