问题
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
思路
基本思路是用二分查找。当找第一个时,如果nums[mid]恰好为target,需要判断mid的左边的数字是否是target,如果是可以往左找;否则直接返回。找最后一个时,同理可得。
代码
class Solution {
public int[] searchRange(int[] nums, int target) {
int low = findLowIndex(nums, target);
int high = findHighIndex(nums, target);
return new int[] {low, high};
}
private int findLowIndex(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int low = 0;
int high = nums.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (nums[mid] == target) {
// mid-1后不要超过low
if (mid - 1 >= low && nums[mid - 1] == target ) {
high = mid - 1;
} else {
return mid;
}
}
if (nums[mid] > target) {
high = mid - 1;
}
if (nums[mid] < target) {
low = mid + 1;
}
}
return -1;
}
private int findHighIndex(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int low = 0;
int high = nums.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (nums[mid] == target) {
if (mid + 1 <= high && nums[mid + 1] == target) {
low = mid + 1;
} else {
return mid;
}
}
if (nums[mid] > target) {
high = mid - 1;
}
if (nums[mid] < target) {
low = mid + 1;
}
}
return -1;
}
}
代码二
public class Solution {
public int[] searchRange(int[] nums, int target) {
int[] result = {-1, -1};
int start = 0;
int end = nums.length - 1;
int mid = 0;
while (start <= end) {
mid = start + ((end - start) >>> 1);
//target < nums[mid]肯定往左找
//找下确界,即使相等也要往左找
if (target <= nums[mid]) {
end = mid - 1;
} else {
//target >= nums[mid]
start = mid + 1;
}
}
if (start < nums.length && nums[start] == target) {
result[0] = start;
end = nums.length - 1;
while (start <= end) {
mid = start + ((end - start) >>> 1);
if (target < nums[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
result[1] = end;
return result;
}
return result;
}
}
官方
官方给的思路:相当于查找第一个大于等于target的下标,和第一个大于target的下标-1。
如果查找第一个大于等于target的下标,只需要在原有二分法中,当大于等于就往左走。
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = binarySearch(nums, target, true);
int right = binarySearch(nums, target, false) - 1;
if (left <= right && nums[left] == target && nums[right] >= target) {
return new int[] {left, right};
}
return new int[] {-1, -1};
}
// 第一个大于target或者第一个大于等于target的下标
private int binarySearch(int[] nums, int target, boolean left) {
int low = 0, high = nums.length - 1;
// 这一步的赋值很关键,不能赋值为-1。
// 有可能nums数字是,1,2,3,4,4,4 target是4 当找上确界时res是无法在循环体中赋值的。
int res = nums.length;
while (low <= high) {
int mid = (low + high) / 2;
if (nums[mid] > target || (left && nums[mid] >= target)) {
high = mid - 1;
res = mid;
} else {
low = mid + 1;
}
}
return res;
}
}
复杂度
时间复杂度:O(logn) 空间复杂度:O(1)
update20210325
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] res = new int[] {-1, -1};
int low = 0;
int high = nums.length - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (nums[mid] == target) {
int i = mid -1;
while (i >= 0 && nums[i] == target) {
i--;
}
res[0] = i+1;
i = mid + 1;
while (i < nums.length && nums[i] == target) {
i++;
}
res[1] = i - 1;
return res;
} else if (nums[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return res;
}
}
update20220106
public int[] searchRange(int[] nums, int target) {
// 分两步:最小的下标和最大的小标
int min = findMinIndex(nums, target);
int max = findMaxIndex(nums, target);
return new int[] {min, max};
}
public int findMinIndex(int[] nums, int target) {
int start = 0, end = nums.length - 1;
int res = -1;
while (start <= end) {
int mid = (start + end) / 2;
if (nums[mid] == target) {
res = mid;
end = mid -1;
} else if (nums[mid] > target) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return res;
}
public int findMaxIndex(int[] nums, int target) {
int start = 0, end = nums.length - 1;
int res = -1;
while (start <= end) {
int mid = (start + end) / 2;
if (nums[mid] == target) {
res = mid;
start = mid + 1;
} else if (nums[mid] < target) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return res;
}
硬广告
欢迎关注公众号:double6
final
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情