为什么这个二分查找排序数组的场景还是会报错呢?

Why is there still an error case in this binary search of sorted array scenario?

郑重声明,我是在某个网络编码网站上遇到这个问题的,但我真正感兴趣的是我错过了什么,而不是分数。开始了:

实现函数 countNumbers,它接受经过排序的唯一整数数组,并计算小于参数 lessThan 的数组元素的数量。

例如SortedSearch.countNumbers(new int[] { 1, 3, 5, 7 }, 4)应该return2因为有两个数组元素小于4.

我给出了以下解决方案,但是,我就是想不通在什么情况下它会失败? (该网站说它在 4 项测试中有 1 项未通过)。而且我也不确定我可以对价值 lessThan.

有什么样的假设
public class SortedSearch {
    public static int countNumbers(int[] sortedArray, int lessThan) {

        if (sortedArray == null || sortedArray.length == 0)
            return 0;

        if (sortedArray.length == 1) {
            return sortedArray[0] < lessThan? 1:0;
        }

        int left = 0;
        int right = sortedArray.length-1;
        int middle = 0;

        while(left<right) {
            middle = left + (right-left)/2;
            if (sortedArray[middle]<lessThan) {
                left = middle+1;
            } else if (sortedArray[middle]>lessThan) {
                right = middle-1;
            } else {
                return middle;
            }        
        }
        return left;

    }

    public static void main(String[] args) {
        System.out.println(SortedSearch.countNumbers(new int[] { 1, 3, 5 }, 4));
    }
}

您的代码当前正在执行经典二分搜索。您需要 修改 以包含您的案例。

例如 使用以下测试用例尝试您的代码:

{ 1, 3, 5 }, 4) -> should output 2
{ 1, 3, 5 }, 2) -> should output 1
{ 1, 3, 5 }, 3) -> should output 1
{ 1, 3, 5 }, 6) -> should output 3
{ 1, 3, 5 }, 0) -> should output 0

其中大部分都因现有代码而失败。

我们的目标是找出 middle 小于 给定数字且 middle + 1 大于 它。当然我们可以使用二进制搜索(修改)来做到这一点。

我修改了经典二进制搜索的代码以包含这些情况(以及代码中添加的注释):

while (left <= right) {
    middle = left + (right - left) / 2;
    if (sortedArray[middle] < lessThan && (middle + 1) < sortedArray.length
            && sortedArray[middle + 1] > lessThan) {
        // we have the point where middle is less and middle+1 is greater than given num
        return middle + 1;
    } else if (sortedArray[middle] == lessThan) {
        // we have found the number itself
        return middle;
    } else if (sortedArray[middle] < lessThan) {
        // recur in right part
        left = middle + 1;
    } else if (sortedArray[middle] > lessThan) {
        // recur in left part
        right = middle - 1;
    }
}

// given number is either lesser/bigger than all elements in the array
return lessThan < sortedArray[0] ? 0 : sortedArray.length;

仅进行 1 更改。

while(left < right)

while(left <= right)

像您这样的二元搜索是我最讨厌的事情之一。我写了我认为通常在这里写一篇的最佳方式:How can I simplify this working Binary Search code in C?

这特别适合您的情况。由于您试图找到一个位置而不是一个元素,因此您可以通过每次迭代只进行一次比较来简化代码并使其更快:

public static int countNumbers(int[] sortedArray, int lessThan) {
    int start = 0, limit = sortedArray.length;
    while(start < limit) {
        int test = start + ((limit-start)>>1);
        if (sortedArray[test] < lessThan) {
            start = test+1;
        } else {
            limit = test;
        }
    }
    return start;
}

请注意,没有特殊情况需要处理,如果数组包含重复元素,这也适用。