【问题标题】:Why is there still an error case in this binary search of sorted array scenario?为什么在这个排序数组场景的二进制搜索中仍然存在错误情况?
【发布时间】:2019-01-25 05:23:10
【问题描述】:

为了记录,我在一些网络编码网站上遇到了这个问题,但我真的对我错过的东西而不是分数感兴趣。就是这样:

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

例如,SortedSearch.countNumbers(new int[] { 1, 3, 5, 7 }, 4) 应该返回 2,因为有两个数组元素小于 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));
    }
}

【问题讨论】:

  • 试试System.out.println(SortedSearch.countNumbers(new int[] { 1, 3 }, 4));
  • 这些挑战的乐趣在于编写自己的测试。这对于使用 junit 做一些工作来说是完美的。简单想想相关的案例,比如:奇数个条目,偶数个,结果应该是0或1的极端案例。只是说:如果这是关于学习,那就把它当作学习测试的机会。
  • 还有更好的方法来写它(在索引或其他方面),这样我就可以在极端情况下写更少的'if'?
  • @user1559625 我们已经回答了您的问题。您能否考虑评论该答案是否对您有帮助,并接受最能回答您问题的答案?
  • @vivek_23 当然,我只是标记了有用的答案,但没有接受一个,因为我仍然对正确性有些怀疑。

标签: java algorithm sorting data-structures binary-search


【解决方案1】:

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

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

{ 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大于的点。当然,我们可以使用二分搜索(修改)来做到这一点。

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

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;

【讨论】:

  • 如果仅将 lessThan 与 sortedArray[0] 进行比较,最后一行句柄“比数组中的所有元素都大”如何?
  • @user1559625 如果代码执行到最后一行,那么很明显找不到我们想要的任何middle 点。所以只剩下两种情况,给定数字小于所有元素或给定数字大于所有元素。
  • 谢谢,还有为什么我们在代码中需要'&& (middle + 1)
  • @user1559625 在条件下避免数组越界异常 -> sortedArray[middle + 1] &gt; lessThan
  • with {1, 3, 5, 7} 4, 最初 left=0, right=3, 最后 left=right=middle=2, and we didn't have '// 我们有重点其中middle小于并且middle+1大于给定的num'。换句话说,使用二分查找我们不能保证在中间target
【解决方案2】:

只更改1

而(左

而(左

【讨论】:

    【解决方案3】:

    像你这样的二进制搜索是我最讨厌的事情之一。我写了我认为通常在这里写一篇文章的最佳方式: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;
    }
    

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

    【讨论】:

      猜你喜欢
      • 2018-06-28
      • 1970-01-01
      • 2018-01-01
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多