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

来源:互联网 发布:二次元图片制作软件 编辑:程序博客网 时间:2024/05/01 15:49

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

0 0
原创粉丝点击