34. 在排序数组中查找元素的第一个和最后一个位置 + 二分查找
题目来源
题目描述
题解分析
解法一:二分法
- 这里与传统的二分法不同,这里需要找到指定元素的左右边界,所以我们无法直接套用二分法的模板。
- 其实,我们可以分别考虑这两种情况,与普通的二分法不同,当需要找左边界时,当我们找到target == nums[mid],我们不是直接返回,而是继续向左找:high = mid - 1;同理,找右边界时,我们继续向右找:low = mid + 1。
class Solution {
public int[] searchRange(int[] nums, int target) {
return new int[]{searchLeft(nums, target), searchRight(nums, target)};
}
private int searchLeft(int[] nums, int target){
int n = nums.length;
int left = 0, right = n-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 >= 0 && left < n && nums[left] == target){
return left;
}
return -1;
}
private int searchRight(int[] nums, int target){
int n = nums.length;
int left = 0, right = n-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 && right < n && nums[right] == target){
return right;
}
return -1;
}
}
解法二:二分法优化
- 考虑到上面的二分法相对比较复杂,它需要定义两个方法,其实这两种情况可以一起考虑。
- 我们可以设置一个变量来保存结果,只不过这个返回的结果需要再额外处理一下,即需要针对左右边界进行修改。
class Solution {
public int[] searchRange(int[] nums, int target) {
if(nums == null || nums.length == 0)
return new int[]{-1, -1};
int low = binarySearch(nums, target, false) + 1;// 左边界需要+1
int high = binarySearch(nums, target, true);// 右边界
if(low <= high && high != -1 && nums[low] == target && nums[high] == target)
return new int[]{low, high};
else return new int[]{-1, -1};
}
public int binarySearch(int[] nums, int target, boolean flag){
int ans = -1;
int low = 0, high = nums.length - 1;
while(low <= high){//这里是小于等于,因为可能一开始数组只有一个元素
int mid = (low + high) / 2;
if((flag && nums[mid] <= target) || nums[mid] < target){
low = mid + 1;
ans = mid;//这步很关键,记录答案的位置
}else{
high = mid - 1;
}
}
return ans;
}
}
Either Excellent or Rusty