下午雨变小了,但我并未去实验室,难得的一天呆在宿舍。有些无聊,看看这个,弄弄那个,听听歌,消磨时间。不知觉中时间指针蹦到了九点,做题啦!朋友推荐了 Eason 的 2010-DUO 演唱会,现在听着 live,敲着键盘。
1、题目描述
2、逻辑分析
题目要求很清晰,递增数组中,给定目标值,找到它的起始位置和结束位置。我的思路是这样的:
首先遍历数组,找到第一个与目标值相等的元素,再继续遍历,找到第一个与目标元素不相等的元素,比如[5,7,7,8,8,10]中,我们要找8的第一个和最后一个位置,那么我们先遍历,找到第一个8,位置索引是3;再继续遍历,找到第一个不等于8的元素10,那么我们需要的数的位置索引就是5 - 1 = 4,由于题目要求了时间复杂度O(logn),所以选择二分查找即可满足需求(其实我没有第一时间想到二分,是敲不出来后看题解才知道滴)。下面看代码演示
3、代码演示
```java
public int[] searchRange(int[] nums, int target) {
// 调用binarySearch方法,搜索target的左边界(即第一次出现的位置)
int leftId = binarySearch(nums, target, true);
// 调用binarySearch方法,搜索target的右边界(即最后一次出现的位置的下一个索引,然后减1)
int rightId = binarySearch(nums, target, false )- 1;
// 检查左边界是否小于等于右边界,并且右边界没有越界,以及左右边界对应的值都等于target
if(leftId <= rightId && rightId < nums.length && nums[leftId] == target && nums[rightId] == target){
// 如果满足条件,返回左右边界的索引数组
return new int []{leftId, rightId};
}else{
// 如果不满足条件,返回[-1, -1]表示没有找到target
return new int []{-1, -1};
}
}
// 二分查找函数,这里引入boolean类型是为了提高复用
public int binarySearch(int[] nums, int target, boolean check ){
// 初始化左右指针和答案变量为数组长度
int left = 0, right = nums.length -1, ans = nums.length;
// 当左指针小于等于右指针时继续搜索
while(left <= right){
int mid = (left + right)/ 2;
// 如果中间值大于target,或者(当check为true时且中间值大于等于target)
if(nums[mid] > target || (check && nums[mid] >= target)){
// 更新答案为当前中间索引
ans = mid;
// 将搜索范围缩小到左半部分
right = mid - 1;
}else{
// 将搜索范围缩小到右半部分
left = mid + 1;
}
}
// 返回最终的答案(左边界或右边界)
return ans;
}
在binarySearch方法中,ans的初始值被设置为nums.length。这是为了确保当目标值大于数组中的所有值时,我们仍然能够返回一个有效的索引(即数组的末尾之后的位置)。
同时,当 check 为 true 时,我们使用 >= 来确保找到的是目标值的第一个出现位置;当 check 为false 时,我们使用 > 来确保找到的是目标值最后出现位置的下一个索引。
最后该算法的时间复杂度:O(logn),空间复杂度:O(1)。
ok啦,雨停了,该去跑六月的第一次步啦,拜拜啦!