二分查找
- 在排序数组中查找元素的第一个和最后一个位置
- 二分查找
- 上期经典算法
在排序数组中查找元素的第一个和最后一个位置
难度 - 中等
在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 1e5
-1e9 <= nums[i] <= 1e9
nums 是一个非递减数组
-1e9 <= target <= 1e9
二分查找
二分查找(Binary Search)是一种在有序数组中查找特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是目标值,则搜索结束;如果目标值大于或小于中间元素,则在数组大于或小于中间元素的那一半中查找,而不是整个数组。以下是这个算法的步骤:
1.将数组按升序或降序排列。
2.找到数组的中间元素。
3.如果中间元素正好是目标值,则结束搜索。
4.如果目标值小于中间元素,那么只需要在数组的左半部分进行搜索。
5.如果目标值大于中间元素,那么只需要在数组的右半部分进行搜索。
6.重复以上步骤,直到找到目标值,或者搜索区域为空。
二分查找的时间复杂度是O(log n),其中n是数组的元素数量,这使得它在大型数据集合中非常高效。然而,它需要数据是预排序的。
在本题中需要对二分查找坐下小小的修改,第三步时,查到目标值结束搜索,因为要查找左右边界,在这一步就不能停,要继续搜索,下面代码演示。
代码演示:
/**
* 找出左右边界
* @param nums
* @param target
* @return
*/
public int[] searchRange(int[] nums, int target) {
//临界条件的判断
if(nums.length == 0 || target < nums[0] || target > nums[nums.length - 1]){
return new int[]{-1,-1};
}
//查找左边界
int left = leftBound(nums,target);
//左边界== -1 时,说明没有target 这个值,也就不用找右边界了。
if(left != -1){
int right = rightBound(nums,target);
return new int[]{left,right};
}
return new int[]{-1,-1};
}
/**
* 查找左边界
* @param nums
* @param target
* @return
*/
public int leftBound(int[]nums,int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left) / 2;
//找到值时,不要直接返回,继续向左搜索
if(nums[mid] == target){
right = mid - 1;
}else if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}
}
if(left >= nums.length){
return -1;
}
return nums[left] == target ? left : -1;
}
/**
* 查找右边界
* @param nums
* @param target
* @return
*/
public int rightBound(int[]nums,int target){
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left) / 2;
//找到目标值,不要立马返回,向右继续搜索。
if(nums[mid] == target){
left = mid + 1;
}else if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid - 1;
}
}
if(right < 0 ){
return -1;
}
return nums[right] == target ? right : -1;
}
上期经典算法
leetcode3. 无重复字符的最长子串