[二分查找] 一:子区间界限应当如何确定

普通的二分查找

先引入一个最简单的二分查找吧

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

很明显,这么写法将每次执行的区间划分为
[left .....mid -1] (mid) [mid+1....right]

那换个写法呢(结果都是正确的)?

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

这个写法将区间分为了左闭右开型,不同于上面的左右两边都是闭区间
[left....mid) (mid) [mid+1....right)

以上两个写法的while条件,一个是left <= right,一个则是left < right

说明第一种while循环的结束条件为left > right,第二种结束条件为left == right

其原因就是因为左闭右闭的区间[i, i]是包含元素nums[i]的,而左闭右开的区间[i, i) 相当于空集。

搞清楚while循环结束时的具体情况,对我们分析边界值非常重要。

当数组中存在多个目标值时,这种方法返回的是位于中间位置那个目标值的下标,但是如果我们想获得目标值第一次出现时的下标应该怎么办呢?

获取左侧边界的二分查找

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

此算法while循环的结束条件为left > right,或者说是left = right + 1,如果nums[left] == target则说明我们最终找到了目标值,而且此时的left是该目标值第一次出现的位置。这种也可以换成子区间左闭右开的写法

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

获取右侧边界的二分查找

原理同上,两种写法

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

int binarySearch_6(int *nums, int numsSize, int target){
    int left = 0, right = numsSize;
    while(left < right){
        int mid = left + (right - left)/2;
        if(nums[mid] == target){
            left = mid + 1;
        }
        else if(nums[mid] > target){
            right = mid;
        }
        else left = mid + 1;
    }
    return nums[right-1] == target? right-1 : -1;
}
int main(){
    int nums[6] = {1,2,2,2,3,5};
    printf("binarySearch_1: %d\n", binarySearch_1(nums, 6, 2));
    printf("binarySearch_2: %d\n", binarySearch_2(nums, 6, 2));
    printf("binarySearch_3: %d\n", binarySearch_3(nums, 6, 2));
    printf("binarySearch_4: %d\n", binarySearch_4(nums, 6, 2));
    printf("binarySearch_5: %d\n", binarySearch_5(nums, 6, 2));
    printf("binarySearch_6: %d\n", binarySearch_6(nums, 6, 2));
    return 0;
}

在这里插入图片描述

“茴香豆”的“茴”字有四种写法,可这二分法有六种写法,孔乙己,得亏你生的早啊。

相关leetcode试题
find-first-and-last-position-of-element-in-sorted-array

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hack Rabbit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值