求数组中频次超过一半的元素

2015某移动电台app秋季面试题
很常见的问题,解决方法有很多,能想到的是:

  1. 快排里面的partition,递归找到中间元素,使得左边元素小于或等于中间元素,右边元素大于或等于中间元素。时间复杂度为O(n),空间复杂度为O(n),原来元素的顺序被打乱了。
  2. hashmap,将数组元素建立hashmap,key为数组元素的值,value为元素出现频次,找到频次出现超过半数的key,复杂度和上述一样

上面两种方法计算复杂度为O(n),但空间复杂度为O(n),不是最优解,下面的方法空间复杂度为O(1):
用两个临时变量,一个保存数组元素,一个记录出现频次。
遍历数组,如果当前元素和临时元素相等,频次加一;
否则减一,如果频次小于1,则临时元素变为当前元素,出现频次变为1。

分析:如果一个数出现频次大于半数,那么它出现的频次必然大于其他所有元素出现的频次,一次遍历后,临时元素保存的肯定是频次超过一半的元素。

代码如下:

//
//  main.cpp
//  moreThanHalf
//
//  Created by LiLingyu on 15/10/20.
//  Copyright © 2015年 LiLingyu. All rights reserved.
//

#include <iostream>

/*
 已知有数组里面有个元素出现次数超过一半,问如何找出这个数,时间复杂度O(n),空间复杂度O(1)
 常见的hashmap时间复杂度为O(n),空间复杂度为O(n),不是最优选
 */
bool isMoreThanHalf(int* a, int len, int number)
{
    int counter = 0;
    for (int i=0; i<len; i++) {
        if (a[i]==number) {
            counter++;
            if (counter*2>len) {
                return true;
            }
        }
    }

    return false;
}

int moreThanHalf(int* a, int len)
{
    int counter = 1;
    int tmp = a[0];
    for (int i=1; i<len; i++) {
        if(a[i]==tmp)
        {
            counter++;
        }
        else
        {
            counter--;
            if (counter<=0) {
                tmp=a[i];
                counter=1;
            }
        }
    }
    /*
    if (counter>=0) {
        return tmp;
    }
    else{
        return -1;
    }*/

    if (isMoreThanHalf(a, len, tmp)) {
        return tmp;
    }
    else
    {
        printf("error: no number appears more than half times!\n");
        return -1;
    }



}

int main(int argc, const char * argv[]) {

    const int len=10;
    int a[len] = {1, 1, 5, 5, 1, 5, 1, 5, 5, 5};
    for (int i=0; i<len; i++) {
        printf("%d\t", a[i]);
    }
    printf("\n");
    printf("result: \n");
    printf("%d\n", moreThanHalf(a, len));
    return 0;
}

下载链接:https://github.com/lilingyu/morethanhalf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值