难度简单1012收藏分享切换为英文接收动态反馈
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
示例 1:
输入:nums
= [-1,0,3,5,9,12],target
= 9 输出: 4 解释: 9 出现在nums
中并且下标为 4
示例 2:
输入:nums
= [-1,0,3,5,9,12],target
= 2 输出: -1 解释: 2 不存在nums
中因此返回 -1
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/binary-search
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第一种是左闭右闭的场景
源代码:
public static int search(int[] nums, int target){
//首先因为数组是有序的,然后是查找元素,所以可以定位成使用二分
int left = 0;//起始左边界
int right = nums.length - 1;//起始右边界
while (right >= left){
//这里是避免越界的一种写法,等同于 (left / 2 + right /2)
int mid = left + (right - left) / 2;
if (nums[mid] == target){
return mid;//存在,返回目标值的位置
} else if (nums[mid] > target){
//当中间值大于目标值,说明此时的目标值一定在mid的左侧,
//所以需要缩小有边界到mid以下,即mid - 1
right = mid - 1;
} else {
//当中间值小于目标值,说明此时的目标值一定在mid的右侧,
//所以需要移动左边界至mid + 1
left = mid + 1;
}
}
return -1;//不存在,则返回-1
}
这里使用的是左闭右闭的区间,即[left,right],所以代码中使用的起始有边界是 nums.length - 1。然后while循环的条件也是 right >= left,right == left的场景也考虑进去,例如{ [1],1},此时的left == right条件成立。
第二种是左闭右开的场景
源代码:
public static int searchTwo(int[] nums, int target){
//首先因为数组是有序的,然后是查找元素,所以可以定位成使用二分
int left = 0;//起始左边界
int right = nums.length;//起始右边界
while (right > left){//当left == right 时候跳出循环
int mid = left + (right - left) / 2;//这里是避免越界的一种写法,等同于 (left / 2 + right /2)
if (nums[mid] == target){
return mid;//存在,返回目标值的位置
} else if (nums[mid] > target){
//当中间值大于目标值,说明此时的目标值一定在mid的左侧,所以需要缩小有边界到mid以下,即mid
right = mid;
} else {
//当中间值小于目标值,说明此时的目标值一定在mid的右侧,所以需要移动左边界至mid + 1
left = mid + 1;
}
}
return -1;//不存在,则返回-1
}
这里与上面的左闭右闭的最主要不同之处在于,起始右边界为nums.length,所以右边界默认成不能使用的,[left,right),后续的所有处理都是按照现在的这个右边界不能使用来处理的,所以right = mid,相比较第一种right = mid - 1的不同之处就是第一种的区间范围是[left,right],区间内所有的值都可以使用,所以每一次的边界值都是和目标值比较之后的mid - 1,第二种的区间范围是[left,right),右边界的值不能使用,所以右边界值更新为mid。