问题 寻找快速计算h指数的算法


http://en.wikipedia.org/wiki/H-index

这个维基页面是h-index的定义

基本上如果我有一个[0 3 4 7 8 9 10]的数组,我的h指数将是4,因为我有4个大于4的数字。如果我有5个,我的h指数将是5数字大于5,等等。给定一个大于或等于0的整数数组,有效计算h指数的方法是什么?

编辑:数组不一定排序


1933
2017-11-22 07:44


起源



答案:


我在这里实现 上) 有表格,这很简单,很快:

private static int GetHIndex(int[] m)
{
    int[] s = new int[m.Length + 1];
    for (int i = 0; i < m.Length; i++) s[Math.Min(m.Length, m[i])]++;

    int sum = 0;
    for (int i = s.Length - 1; i >= 0; i--)
    {
        sum += s[i];
        if (sum >= i)
            return i;
    }

    return 0;
}

11
2017-11-22 09:38



好解决方案! +1 - ElKamina
这个算法错了,应该是 if(sum == i) return i;。但即便如此,它还是计算出来的 i 数字更大 或者相等 比 i (根据链接的内容是正确的,但不是提问者想知道的内容)。此外,如果没有匹配(因此 return) 在第二 for 循环算法返回 0 这意味着零数字(或大于或等于)大于零,这与仅包含大于或等于0的数字的(非空)数组相矛盾(至少如果使用关系检查) >= 因为现在已经完成了)。 - a_guest
没意见?没解释?算法可能不错,但不要强迫读者盯着它,至少要分享核心思想。 - timgeb


答案:


我在这里实现 上) 有表格,这很简单,很快:

private static int GetHIndex(int[] m)
{
    int[] s = new int[m.Length + 1];
    for (int i = 0; i < m.Length; i++) s[Math.Min(m.Length, m[i])]++;

    int sum = 0;
    for (int i = s.Length - 1; i >= 0; i--)
    {
        sum += s[i];
        if (sum >= i)
            return i;
    }

    return 0;
}

11
2017-11-22 09:38



好解决方案! +1 - ElKamina
这个算法错了,应该是 if(sum == i) return i;。但即便如此,它还是计算出来的 i 数字更大 或者相等 比 i (根据链接的内容是正确的,但不是提问者想知道的内容)。此外,如果没有匹配(因此 return) 在第二 for 循环算法返回 0 这意味着零数字(或大于或等于)大于零,这与仅包含大于或等于0的数字的(非空)数组相矛盾(至少如果使用关系检查) >= 因为现在已经完成了)。 - a_guest
没意见?没解释?算法可能不错,但不要强迫读者盯着它,至少要分享核心思想。 - timgeb


这可以在O(n)时间内完成。

  1. 找到数组的中位数。
  2. 如果中位数>(n-1)/ 2则数字在中位数之前。迭代地找到它
  3. 如果中位数<(n-1)/ 2,则数字在中位数之后。迭代地找到它。
  4. 如果中位数==(n-1)/ 2则中位数是解

在这里我假设n是奇数。偶数n改变算法(假设中位数为n / 2,则用n / 2替换(n + 1)/ 2)。而且,在O(n)时间内找到实际中值是复杂的。改为使用好的支点(如快速排序)。

复杂度:n + n / 2 + n / 4 ... = O(n)


1
2017-11-22 08:03



awsome = D,我猜线性是最好的结果 - cakester
这是NLogN,因为中位数的搜索应该在所有数组中完成。 - Толя
回答不在数组内的情况怎么样?示例[0 0 0 9 9 9] - Толя
@Толя当你只剩下1个元素并且这不是正确的解决方案时,那么就没有解决方案。 - ElKamina
@Vikram Bhat 1/2 + 1/4 + ......(直到无穷大)= 1,所以它和ElKamina一样写道:O(n)。 - artur grzesiak


这是我能想到的一个解决方案。不确定它是否是最好的。

按升序对数组进行排序。复杂 n日志(n)的

迭代索引中的数组 0到n。复杂性 ñ

并且对于每次迭代,假设索引是 一世

if (arr[i] == (arr.length - (i+1))
    return arr[i]

例如。,

arr =[ 0 3 4 7 8 9 10 ]
arr[2] = 4
i = 2
arr.length = 7
4 = (7- (2+1))

0
2017-11-22 08:03



无需排序(O(nlogn))。看我的解决方案是O(n) - ElKamina
分类 在 O(log N) ?真?你必须是天才。 - Alma Do
对不起。 :)这是一个错字 - vishnu viswanath
@ElKamina。你的答案更好 - vishnu viswanath
这个算法是错误的,因为它只会返回一个结果,如果实际的h-index是数组的一部分。添加号码 11 举个例子([0, 3, 4, 7, 8, 9, 10, 11])应该返回解决方案 5 因为有五个数字大于5但这个算法找不到解决方案。 - a_guest


我对我以前的实现不满意,所以我用一个用Java编写的更快的解决方案取而代之。

public int hIndex(int[] citations) {
    if(citations == null || citations.length == 0)
    {
        return 0;
    }

    Arrays.sort(citations);

    int hIndex = 0;

    for(int i=0;i<citations.length;i++)
    {
        int hNew;

        if(citations[i]<citations.length-i)
        {
            hNew = citations[i];

            if(hNew>hIndex)
            {
                hIndex = hNew;
            }
        }
        else if(citations[i]>=citations.length-i)
        {
            hNew = citations.length-i;

            if(hNew>hIndex)
            {
                hIndex = hNew;
            }

            break;
        }
    }

    return hIndex;
}

-1
2017-09-09 09:05