【剑指 offer】(二十九)—— 数组中出现次数超过一半的数字(及该数字出现的次数)

来源:互联网 发布:mac 命令行安装wget 编辑:程序博客网 时间:2024/06/03 19:18

题目:数组中有一个数字出现的次数超过数组长度的一半,请找出该数字,如输入一个长度为 9 的数组 {1, 2, 3, 2, 2, 2, 5, 4, 2}。由于数字 2 在数组中出现了 5 次(5>9/2),超出数组长度的一半,因此输出为2.

思路 1:统计计数,

统计每一个元素出现的次数,时间复杂度为 O(n)。如果某元素出现的次数超过 n/2,直接输出,不可能有第二个元素出现的次数还超过 n/2。

数据结构的选择,因为我们不知道数组中元素的大致范围,所以如果使用简单的数据建立元素和出现次数的映射的话,无法事先确定数组的长度。我们使用字典建立映射:

int moreThanOneHalf(int* data, int n){    map<int, int> times;    for (int i = 0; i < n; ++i)        ++times[data[i]];    for (const pair<int, int>& e: times)        if (e.second > n/2)            return e.first;}

思路 2:

我们可以考虑在遍历数组的时候保存两个值:一个是数组的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1;如果不同,则减一。如果次数为0,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么遍历到最后得到的数字就是我们要找的数字。

int MoreThanOneHalf(int* data, int n){    int res = data[0];    int times = 0;    for (int i = 1; i < n; ++i)    {        if (times == 0)             res = data[i];        if (data[i] != res)            --times;        else            ++times;    }    return res;}

分析

巧的是,以上两种思路,均可获得出现次数最多元素出现的次数,思路 1 很明显:

const pair<int, int>& MoreThanOneHalf(int* data, int n){    //...    for (const pair<int, int>& e: times)        if (e.second > n/2)            return e;}

思路二最后得到的 times,表示的是出现次数最多的元素出现的次数,比其他全部元素多出来的出现次数,应用一元一次方程,

x-(n-x)=k ⇒ x = (n+k)/2
pair<int, int> MoreThanOneHalf(int* data, int n){    ....    return make_pair(res, (n+times)/2);}
0 0
原创粉丝点击