本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
题目描述
来源:力扣(LeetCode)
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
- 你可以设计并实现时间复杂度为
O(log n)的算法解决此问题吗?
示例 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]
提示:
0 <= nums.length <= 105-109 <= nums[i] <= 109nums是一个非递减数组-109 <= target <= 109
题目分析
一般解法
话不多说,直接就从左到右遍历一遍,先找到第一个与target的元素,再找第二个
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] result = {-1,-1};
int len = nums.length;
if(len == 0 || nums[0] > target || nums[len - 1] < target){
return result;
}
boolean flag = true;
for (int i = 0; i < len; i++) {
if (nums[i] == target){
if(flag){
result[0] = i;
flag = false;
}
}
if(!flag && nums[i] != target) {
result[1] = i - 1;
break;
}
}
if((len == 1 && nums[0] == target)){
result[1] = 0;
}
if(nums[len - 1] == target) {
result[1] = len - 1;
}
return result;
}
}
时间复杂度为O(n),然后挑战一下复杂度为 O(log n) 的解法
二分查找
-
有序和数组这个两个字眼结合起来,肯定是要用到二分查找
-
首先就是找最左侧的下标,利用二分查找首先是找到有一个值是与目标值target是相等的,然后因为是找最左侧的下标,所以把right=mid-1来一直往左边去逼近最左侧的值
-
至于找最右侧的下标就是,将left=mid+1,来去逼近最右侧的下标
-
如果没有找到则说明不存在返回-1
class Solution {
public int[] searchRange(int[] nums, int target) {
int [] result = {-1,-1};
result[0] = findLeftIndex(nums,target);
result[1] = findRightIndex(nums,0,target);
return result;
}
public int findLeftIndex(int [] nums,int target)
{
int left = 0;
int right = nums.length - 1;
int leftIndex = -1;
while(left <= right)
{
int mid = left + (right - left) / 2;
if(nums[mid] < target)
{
left = mid + 1;
}else if(nums[mid] > target)
{
right = mid - 1;
}else{
leftIndex = mid;
right = mid - 1;
}
}
return leftIndex;
}
public int findRightIndex(int [] nums,int left,int target)
{
int right = nums.length - 1;
int rightIndex = -1;
while(left <= right)
{
int mid = left + (right - left) / 2;
if(nums[mid] < target)
{
left = mid + 1;
}else if(nums[mid] > target)
{
right = mid - 1;
}else{
rightIndex = mid;
left = mid + 1;
}
}
return rightIndex;
}
}
总结
这种解法思路还是很清晰的,只是一些边界条件需要判断。二分查找的时间复杂度为 O(\log n)
这里简单写一下二分查找,比如对于数组[1,2,4,4,4,4,4,5,6],找4的最左下标。
-
对于这个数目来说,left,right,mid分别代表下标值首先left=0,right=8,所以mid=(0+8)/2 = 4;
-
由于target=4与nums[mid]相等,所以此时记录下来这个下标,也就是mid的值4,这个下标是可能的最左的4的下标所以要记录保存一下;
-
观察这个数组,可以知道,最左的4的下标是2,所以为了找到这个最左的下标,需要令right的值去等于mid-1;这样就把right这一边慢慢地往左靠,因为是找最左的嘛,所以肯定是要缩小right的的值去逼近这个最左的4,直到找到这个最左的4为止;
-
找最右边的4的思路也是一样的,就是令left=mid+1去逼近最右边的这个4.