更好的算法用于查找元素的重复次数,给定一个排序数组,其中元素重复任何否。时间

时间:2011-06-28 09:10:46

标签: algorithm

我已尝试对给定元素进行二元搜索,并向左和向右遍历它,直到它得到的元素大于或小于它,但如果所有元素都相同,则直到O(n)时间复杂度。可以有更好的算法吗。

5 个答案:

答案 0 :(得分:5)

您可以使用二进制搜索来查找范围的下限(和/或上限),并对下限进行二进制搜索,并对元素范围的上限或下限进行搜索大于你关心的那个。

编辑:我发现找到下限的大部分代码(我相信)比实际需要的要复杂得多。

int *find(int *left, int *right, int val) {
    assert(left<right);
    while (left < right) {
        int *middle = left + (right - left) / 2;
        if (*middle < val)
            left = middle + 1;
        else
            right = middle;
    }
    return left;
}

答案 1 :(得分:3)

进行两次二进制搜索:

在第一次搜索中,如果中间元素等于所搜索的元素,则选择左半部分。

在第二次搜索中,如果中间元素等于所搜索的元素,则选择右半部分。

Java中的示例代码:

class Test {

    public static int findElem(int[] arr, int elem, int l, int h,boolean first) {
        if (h - l <= 1)
            return first ? (arr[l] == elem ? l : h) : (arr[h] == elem ? h : l);

        int m = l + (h - l) / 2;

        if (arr[m] < elem || (arr[m] == elem && !first))
            return findElem(arr, elem, m, h, first);

        return findElem(arr, elem, l, m, first);
    }

    public static int findElem(int[] arr, int elem, boolean first) {
        return findElem(arr, elem, 0, arr.length, first);
    }

    public static void main(String[] args) {
        int[] arr = { 0, 1, 2, 2, 2, 3, 3, 4, 4, 5 };

        int elem = 2;

        System.out.println("First index: " + findElem(arr, elem, true));
        System.out.println("Last index : " + findElem(arr, elem, false));
    }
}

答案 2 :(得分:1)

您应该二进制搜索匹配序列的第一个和最后一个元素。如果您使用的是C ++,那么STL中有lower_boundupper_bound等功能可以让您这样做。否则,这是对算法的简单修改。

或者,您可以使用3个二进制搜索:

  1. 二进制搜索与您的值匹配的任何元素
  2. 二进制搜索范围的左侧
  3. 二进制搜索范围的右侧
  4. 然而,能够做到最后2意味着你已经实现了第一个解决方案(通过找到下限/上限)

答案 3 :(得分:0)

如果要多次执行此操作,可以创建一个哈希表,其中元素值为键,第一个和最后一个元素的索引为值。

读取数据以创建哈希表是O(n)操作,但是查找索引接近于O(1)操作。

答案 4 :(得分:0)

假设您有anT元素的排序数组x。然后对于某个元素T* ub = upper_bound( a, a + n, x ); int answer = ub - lower_bound( a, ub, x ); ,您可以按如下方式找到它的重复次数:

O(logn)

复杂性显然是x。当所有元素相同或a中没有元素upper_bound时,a+n将返回lower_bound2 * logn将在整个时间间隔内工作,将针对这些最糟糕的情况进行{{1}}次迭代。