前言
力扣第三十四题 在排序数组中查找元素的第一个和最后一个位置 如下所示:
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
示例 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]
一、思路
在仔细阅读题目后,可以得到以下两个重要的信息:
- 升序排列数组
- 找到目标值的位置(开始和结束位置)
可以先忽略要寻找目标值开始和结束的位置,对于升序数组来找目标值的位置来说,使用 二分法 是最好的选择。
实现的思路大致可以分为以下两个步骤:
- 使用二分法找到目标值的位置
p,即nums[p] == target - 从位置
p向前找到开始的位置,再从p向后找到结束位置
举个例子
此处以示例1中的 nums = [5,7,7,8,8,10], target = 8 作为例子
p = -1:目标值的位置,初始值为 -1
left = 0:二分法左边界
right = nums.lengt - 1:二分法右边界
具体的步骤如下所示:
mid = (left + right)/2 = 2,此时nums[mid] < target,说明在右半边。left = mid + 1 = 3mid = (left + right)/2 = 4,此时nums[mid] == target,找到了目标位置p = 4- 从位置
p向前,nums[3] == target - 继续向前,
nums[2] != target,说明开始位置为3 - 从位置
p向后,nums[5] != target,说明结束位置为4 - 返回结果
3和4
二、实现
实现方式与思路保持一致,但是要注意如果二分法没有找到目标值,则直接返回结果即可
实现代码
/**
* 二分法
*/
public int[] searchRange(int[] nums, int target) {
int[] ret = {-1, -1};
int len = nums.length;
int left = 0;
int right = len - 1;
// 先找到target的所在位置
int p = -1;
while (left <= right) {
int mid = (left + right)/2;
if (nums[mid] == target) {
p = mid;
break;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
// 判断是否找到
if (p != -1) {
// 向前寻找
int i = p;
int j = p;
// 向前寻找
for (; i>-1; i--) {
if (nums[i] != target)
break;
}
// 向后
for (; j<nums.length; j++) {
if (nums[j] != target)
break;
}
// 赋值
ret[0] = i + 1;
ret[1] = j - 1;
}
return ret;
}
测试代码
public static void main(String[] args) {
int[] nums = {5,7,7,8,8,10};
int target = 8;
new Number34().searchRange(nums, target);
}
结果
三、总结
一般来说在升序或者降序的数组中找到目标值,使用 二分法 会是一个不错的选择!
感谢看到最后,非常荣幸能够帮助到你~♥