题目描述:
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array
著作权归领扣网络所有。
栗子1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
栗子2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
思路:
看到题目之后,你最先想到的可能是for循环去遍历,可是本题对时间复杂度有一定的要求,所以此路不通。
时间复杂度必须是O(log n) ,再加上数据结构是升序排列的数组,那么很容易就联想到二分查找算法了。有没有“柳暗花明又一村”的感觉呢?
不过读完题之后,你会发现这和我们当初学习的二分查找还不太一样。当初二分查找返回的是目标值所在数组对应的下标,不存在则返回-1。所以呢,本题是二分查找的一个变形题目。如果你不清楚最基础的二分查找,可以先去看一下资料,之后再看这道题就会事半功倍。
这里呢,我认为你已经了解了二分查找算法,所以主要来讲一下寻找目标值的一些情况。数组的默认值最后说明哈,我们先从中间值左面的检索说起。中间值为mid,前一个元素就是mid-1,当mid-1=0的时候说明mid前面是有值的,属于需要检索的范围,如果mid-1<0,那么便超出了边界,可以终止检索。因为我们要找的是目标值第一次出现的位置,所以值需要等于目标值,在满足这两个条件的情况下进行检索。从中间值向右的检索也是一个道理。如果检索的过程中,发现了目标值,那么皆大欢喜。我们把它放到结果数组中即可,可是要是没找到怎么办呢?
如果中间值的左面和右面都没有目标值,那么我们返回什么呢?当然是{mid,mid}了,为什么?因为只有nums[mid]==target目标值的时候才会走进这个else语句,而且只有一个目标值。就好像{1,2,3},target=2;也有可能左面会有返回值,右面没有,就像{0,2,2,3,4},target=2;也有可能右面会有返回值,左面没有,就像{0,1,2,2,3},target=2。这样子是不是就可以想通了?
如果有什么错误或者问题,欢迎评论,我们一起探讨,一起进步。
代码:
public static int[] searchRange(int[] nums, int target) {
int low = 0;
int high = nums.length - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (nums[mid] < target) {
low = mid + 1;
} else if (nums[mid] > target) {
high = mid - 1;
} else {
//注意
int[] a = {mid, mid};
//中间值向左检索(不包含中间值)
int tmp = mid - 1;
while (tmp >= 0 && nums[tmp] == target) {
a[0] = tmp;
tmp--;
}
//中间值向右检索(不包含中间值)
tmp = mid + 1;
while (tmp <= nums.length - 1 && nums[tmp] == target) {
a[1] = tmp;
tmp++;
}
//最终结果
return a;
}
}
return new int[]{-1, -1};
}