力扣 查找元素的位置
二分查找经典例题。
题目
要是只是从数组中用二分查找对应的元素,套一下模板一下就可以得出了,然后这题就在于其中会有多个目标元素,要用不同的方式在找到第一个元素时再做偏移。
时间复杂度:O(log n),空间复杂度:O(1)。
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int first = -1;
int last = -1;
// 找第一个等于target的位置
while (left <= right) {
int middle = (left + right) / 2;
if (nums[middle] == target) {
first = middle;
right = middle - 1; //找到后继续往左,直到找到第一个等于target的位置
} else if (nums[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
// 最后一个等于target的位置
left = 0;
right = nums.length - 1;
while (left <= right) {
int middle = (left + right) / 2;
if (nums[middle] == target) {
last = middle;
left = middle + 1; //找到后继续往右,直到找到最后一个等于target的位置
} else if (nums[middle] > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return new int[]{first, last};
}
}
接着也可以套常见的两种二分模板。
一种是将区间[l,r]划分成[l,mid]和[mid+1,r]时,其更新操作是r=mid或者l=mid+1,计算mid时不需要加1,即mid=(l+r)/2。
while (l < r)
{
int mid = (l + r)/2;
if (check(mid)) r = mid;
else l = mid + 1;
}
一种是将区间[l,r]划分成[l,mid−1]和[mid,r]时,其更新操作是r=mid−1或者l=mid,此时为了防止不断循环,计算mid时需要加1,即mid=(l+r+1)/2。
while (l < r)
{
int mid = ( l + r + 1 ) /2;
if (check(mid)) l = mid;
else r = mid - 1;
}
然后用两种不同的二分查找方式即可以找到数组中目标元素的第一个和最后一个位置了。
时间复杂度:O(log n),空间复杂度:O(1)。
class Solution {
public int[] searchRange(int[] nums, int target) {
if(nums.length == 0) return new int[]{-1,-1};
int low = 0, r = nums.length - 1;
while( l < r)
{
int mid = (l + r )/2;
if(nums[mid] >= target) r = mid;
else l = mid + 1;
}
if( nums[r] != target) return new int[]{-1,-1};
int L = r;
l = 0; r = nums.length - 1;
while( l < r)
{
int mid = (l + r +1)/2;
if(nums[mid] <= target ) l = mid;
else r = mid - 1;
}
return new int[]{L,r};
}
}