我的二进制搜索代码太慢了

时间:2016-12-01 17:17:44

标签: java algorithm binary-search

我正在尝试解决this算法任务。当我提交我的代码时,在某些测试用例中,我的代码太慢了,而在我的代码中,我的代码输出错误。我试图找到我犯错的地方,但我真的无能为力。因为在我的代码失败的测试用例中,有更多的长度数组,我无法检查每个输出以找出错误。

所以我想知道你是否可以给我一些建议:

  1. 如何提高算法效率。
  2. 如果我在某些测试用例中出错,那么输出错误。
  3. 这是我的代码:

    public class Main
    {   
    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);
        int length = sc.nextInt();
        int arr[] = new int[length];
    
        for(int i=0; i<length; i++)
            arr[i] = sc.nextInt();
    
        int test = sc.nextInt();
        int type, check;
    
        for(int i=0; i<test; i++)
        {
            type = sc.nextInt();
            check = sc.nextInt();
    
            if(type == 0)
            {
                System.out.println(greaterOrEqualThan(arr, check, length));
            }
            else if(type == 1)
            {
                System.out.println(greaterThan(arr, check, length));
            }
        }
    }
    
    public static int greaterThan(int arr[],int x, int length)
    {
        int low = 0;
        int high = length-1;
        int mid;
    
        while( low+1 < high)
        {
            mid = (high+low)/2;
    
            if(arr[mid] <= x)
                low = mid;
            else if(arr[mid] > x)
                high = mid;
        }
        int startIndex;
    
        if(arr[low] > x && arr[low] != arr[high])
            startIndex = low;
        else if(arr[high] > x && arr[high] != arr[low])
            startIndex = high;
        else
            return 0;
    
        return length-startIndex;
    }
    
    public static int greaterOrEqualThan(int arr[], int x, int length)
    {
        int low = 0;
        int high = length-1;
        int mid;
    
        while(low+1 < high)
        {
            mid = (low+high)/2;
    
            if(arr[mid] < x)
                low = mid;
            else if(arr[mid] == x)
            {
                high = mid;
                break;
            }
            else
                high = mid;
        }
    
        int startIndex;
    
        if(arr[low] >= x)
            startIndex = low;
        else if(arr[high] >= x)
            startIndex = high;
        else
            return 0;
    
        return length-(startIndex);
    }
    }
    

1 个答案:

答案 0 :(得分:2)

我认为在阵列中存在多个目标值实例的情况下,您的一个或两个算法可能不正确。 (例如[1,3,3,3,5]

三个需要考虑的案例

有三种情况需要考虑:

  1. x未在数组中出现
  2. x恰好在数组中出现一次
  3. x不止一次出现在数组中
  4. 如何解决

    我建议对两种方法中的每种方法使用经典的二进制搜索算法(精确的二进制搜索算法,无需修改)。之后你所做的就是与众不同。

    首先,运行经典的二进制搜索算法,直接内联到您的方法中(这样您就可以访问lowhigh的终端值。

    其次,在二进制搜索终止后,测试array[mid] != x。如果array[mid] != x,那么数组中不会出现x,而low == high + 1(自highlow已经过了。{'}}数组中不小于x的数字和数组中大于x的数字都等于array.length - low

    第三,如果array[mid] == x为真,那么x确实会在数组中出现一次或多次。由于经典的二进制搜索算法会在找到x时立即终止,因此它终止于其中的“x不确定”。

    在这种情况下,为了找到不小于x的数字计数,您必须使用以下代码段找到数组中的“第一个”x

    do {
        mid = mid - 1;
    } while (array[mid] == x);
    
    然后

    mid将成为数组中“第一个”x之前的元素的索引,因此数字的计数不小于{{1将是x

    同样,为了找到大于array.length - mid + 1的数字计数,您必须首先使用以下代码段找到数组中的“last”x

    x
    然后

    do { mid = mid + 1; } while (array[mid] == x); 将成为数组中“最后一个”mid之后的元素的索引,因此大于{{1}的数字的数量将是x

    代码

    经典二进制搜索的简化内联版本

    x

    不小于x

    array.length - mid - 1

    大于x

    int low = 0;
    int high = array.length - 1;
    int mid = (high + low) / 2;  // priming read
    
    while (array[mid] != x && low <= high) {
        if (array[mid] > x)
            high = mid - 1;
        else   // (array[mid] < x)
            low = mid + 1;
        mid = (high - mid) / 2;
    }