二分法查找while、if条件,透过区间本质带你吃透

392 阅读2分钟

前序

二分法是很重要并且非常基础的查找算法,为什么很多同学对于它都是,一看就会,一写就费,接下来,花上几分钟,把这几个小细节抓透。

区间的定义

在开始手撕二分法之前,我们来谈一谈区间的问题。区间的左端点,右端点的情况,一共有三种:左闭右闭 [ ],左闭右开[ ),还有左开右闭[ )

了解了这三种区间端点的定义后,我们就从这些定义中,用一个例子,直截了当地一眼写出while语句的判断条件。 因为左闭右开的区间可以两个端点值都取到,所以它的右边就可以相当于“<=”的作用,而左闭右开,或者左开右闭的区间,它的“(”或者“)”就相当于“>”或者“<”对应的端点值。下面用一段简单的二分查找代码来进一步让这个概念更加清晰。

int search(int* nums, int numsSize, int target){
    int left = 0;
    int right = numsSize-1;
    int middle = 0;
    while(left<=right) {
        middle = (left+right)/2;
        if(nums[middle] > target) {
            right = middle-1;
        } 
        else if(nums[middle] < target) {
            left = middle+1;
        } 
        else if(nums[middle] == target){
            return middle;
        }
    }
    return -1;
}

主函数中定义一个search方法,传入一个数组(升序),数组长度,和目标数值,注意! 此时我们定义的right为数组长度(numsSizs)-1,此时target是在左闭右闭[left,right]的区间中,当left == right时是有意义的,所以while循环的判断条件要用“<=”

当我们要进入下一次if中时,我们可以断定当前的nums[middle]的下标middle必然不是我们要查找的值的下标,所以当下一次while时,就可以不用将这时的下标middle加入判断中。if判断nums[middle] > target时,将下一次进入while循环中的right = middle-1;nums[middle] < target时,left=middle-1,因为是左边的后一位,右边的前一位,最后找到nums[middle] == target,返回 middle目标值target的下标,未找到则返回-1。

我们来看有开区间的情况

int search(int* nums, int numsSize, int target){
    int left = 0;
    int right = numsSize;	
    int middle = 0;
    while(left < right){  
        int middle = left + (right - left) / 2;
        if(nums[middle] < target){
            left = middle + 1;
        }else if(nums[middle] > target){

            right = middle ;
        }else{	
            return middle;
        }
    }
    return -1;
}

这时的right = numsSize,此时target在[left,right)区间中,当left == right时,根据区间的定义,右边端点是取不到的,此时while的判断条件就为“<”。if的判断条件是一样的。

左开右闭的情况在大型项目中不常见,在平时的算法题目中也不多,它的原理和[left,right)是相同的,这里就不再赘述,让干货最干。