求數組中頻次超過一半的元素

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章