GDUT-1164-找出出现次数超过一半的数

来源:互联网 发布:众泰e200和知豆d2s 编辑:程序博客网 时间:2024/06/11 01:52

ACM模版

描述

描述

题解

很有趣的一道题,不算难,但是和几个朋友讨论这道题涨了些许姿势~~~

首先,这道题如果用 map 写,理论上会超时,本来这样就是小题大做。比较直观的是 sort 一下,然后扫描一下就好了,但是如果只是这样也就没有讨论的必要了,试图寻找更好的解题思路时,我的思维过于局限,局限在了计数上,当然并不是说计数就无法更优,只是我没有参透些许。

经过讨论,有四种不错的思路:
第一种,多重 HASH 搞;
第二种,不断从数组中取数对,每次都取不同的两个数,直到无法再取,那么剩下的就是答案;
第三种,其实这个问题转换一下就是求第 K 大数的问题,不过这里的 K 等于 (n + 1) / 2,解题思路和快排相似;
第四种,也是我所给出的代码,虽然我一直执着于计数,感觉计数很难实现更快的解法,但是这个解法依然是计数,效率却高了很多,是 O(N),具体思维也就是缩放计数,原题因为数据范围为1e9太大无法开数组计数,导致复杂度难以降低,就着这个思维,如何将其缩小,以满足可以开数组计数,其实这里可以理解为将高位和低位拆解开,高位的先计数,然后从满足高位计数条件的结果中进行低位的计数,最后选取低位计数中的符合要求的结果即可,还有略微的优化空间,但是思路十分不错,还是我的道行太低!!!

代码

#include <cstdio>#include <algorithm>#include <cstring>#define MAXN 10000005#define BASE 1000using namespace std;int A[MAXN];int cnt[MAXN / 10];int deep[BASE + 10];int main(){    int T;    scanf("%d", &T);    while (T--)    {        memset(cnt, 0, sizeof(cnt));        memset(deep, 0, sizeof(deep));        int n, a, b, res = 0;        scanf("%d", &n);        for (int i = 0; i < n; i++)        {            scanf("%d", A + i);            b = A[i] / BASE;            cnt[b]++;            res = (cnt[res] < cnt[b]) ? b : res;        }        int g = 0;        for (int i = 0; i < n; i++)        {            if (A[i] / BASE == res)            {                a = A[i] % BASE;                deep[a]++;                g = (deep[g] < deep[a]) ? a : g;            }        }        printf("%d\n", g + res * 1000);    }    return 0;}
0 0