在排序的整数数组中搜索等于其索引的元素,其中A可能具有重复的条目

时间:2015-05-10 01:30:08

标签: algorithm search

我的问题与Q1Q2非常相似,只是我想处理数组可能有重复条目的情况。

假设数组A由按升序排序的整数组成。如果它的条目都是不同的,您可以使用二进制搜索在O(log n)中轻松完成。但是如果有重复的条目,那就更复杂了。这是我的方法:

int search(const vector<int>& A) {
    int left = 0, right = A.size() - 1;
    return binarySearchHelper(A, left, right);
}

int binarySearchHelper(const vector<int>& A, int left, int right) {
    int indexFound = -1;
    if (left <= right) {
        int mid = left + (right - left) / 2;
        if (A[mid] == mid) {
            return mid;
        } else {
            if (A[mid] <= right) {
                indexFound = binarySearchHelper(A, mid + 1, right);
            }
            if (indexFound == -1 && A[left] <= mid) {
                indexFound = binarySearchHelper(A, left, mid - 1);
            }
        }
    }
    return indexFound;    
}

在最坏的情况下(A没有等于其索引的元素),binarySearchHelper进行2次递归调用,在每个递归级别输入大小减半,这意味着它的最坏情况时间复杂度为O(n )。这与O(n)方法相同,您只需按顺序读取数组。这真的是你能做的最好的吗?另外,有没有办法测量算法的平均时间复杂度?如果没有,是否有一些启发式方法来决定何时使用基本的O(n)直读方法以及何时尝试递归方法,例如我的?

如果A有负整数,则需要检查if (left <= right)中的条件binarySearchHelper。例如,如果A = [-1],那么算法会从bsh(A, 0, 0)递归到bsh(A,1,0)bsh(A,0,-1)。我的直觉使我相信支票if (left <= right)是必要的,当且仅当A有一些负整数。任何人都可以帮我核实一下吗?

1 个答案:

答案 0 :(得分:2)

我会采取不同的方法。首先,我将通过对第一个正数进行二进制搜索来消除 O(log n)中的所有负数。这是允许的,因为没有负数可以等于其索引。让我们说第一个正元素的索引是i

现在我将继续执行以下操作,直到找到该元素或发现它不存在:

  1. 如果i不在A内,则返回false。
  2. 如果i < A[i]i = A[i]。需要A[i] - i重复才能让i赶上&#39;到A[i],我们会i增加A[i] - i,这相当于将i设置为A[i]。转到1.
  3. 如果i == A[i]返回true(如果您愿意,则返回索引)。
  4. 查找大于i的第一个索引i <= A[i]。你可以这样做从左边做一个二进制搜索&#39;通过将i递增1,2,4,8等,然后在找到它的最后一个间隔进行二进制搜索。如果它不存在,则返回false。
  5. 在最糟糕的情况下,上面的结论是 O(n),但是在更好的情况下,它有很多技巧可以加快速度。