在排序数组中查找元素的第一个和最后一个元素
https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/
题目描述:
给定一个按照升序排列的整数数组 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]
解题思路:
由于题目已经给了算法的时间复杂度的要求,所以不能使用遍历的方式来完成,遍历的时间复杂度最小是O(log(n))
在排序数组中查找元素就要充分利用已经有序的特点,所以采用二分查找的方式进行查找。
二分查找某个元素在数组中是否存在:
定义left和right分别为数组的开始和结尾,只要left<= right 一直进行循环
每次更新mid的值
如果要找的数大于mid位置的数,就在数组的后半段找;
如果要找的数小于mid位置的数,在数组的前半段找
直到mid位置的数等于要找的数,返回mid
如果没有找到就返回-1
public int BinarySearch(int[] nums,int target){
int left = 0;
int right = nums.length-1;
while (left <= right){
int mid = (left + right)/2;
//mid = left + (right -left)/2;//不会溢出
if (nums[mid] == target){
return mid;
}else if(nums[mid] > target){
left = mid +1;
}else if(nums[mid] < target){
right = mid-1;
}
}
return -1;
}
要找到第一个元素和最后一个元素相当于确定区间的左边界和右边界
只要left< right ,就可以进行下面的分析
左边界:(return left)
- nums[mid] = target: right = mid -1
- nums[mid] > target: right = mid-1
- nums[mid] < target: left = mid +1
右边界:(return right)
- nums[mid] = target: left= mid +1
- nums[mid] > target: right = mid-1
- nums[mid] < target: left = mid +1
特殊情况:
很小的数——右边界越界【right == -1】
很大的数——左边界越界【left == nums.length】
在范围内的数但不在数组中——判断要返回的值是不是和target相等
代码实现:
public class Solution {
public int[] searchRange(int[] nums, int target) {
int[] result = new int[2];
int leftIndex = getLeft(nums,target);
int rightIndex =getRight(nums,target);
result[0] =leftIndex;
result[1] = rightIndex;
return result;
}
//找左边界
public int getLeft(int[] nums ,int target){
int left =0;
int right = nums.length-1;
int mid =0;
while (left <= right){
mid = (left+right)/2;
if (nums[mid] == target){
right = mid-1;
}else if(nums[mid] < target){
left = mid +1;
}else if (nums[mid] > target){
right = mid -1;
}
}
//边界情况
if (left == nums.length || nums[left] != target ){
return -1;
}
return left;
}
//找右边界
public int getRight(int[] nums ,int target){
int left =0;
int right = nums.length-1;
int mid =0;
while (left <= right) {
mid = (left + right) / 2;
if (nums[mid] == target){
left = mid+1;
}else if (nums[mid] < target){
left = mid+1;
}else if(nums[mid] > target){
right = mid -1;
}
}
//边界情况
if ( right == -1 || nums[right] != target){
return -1;
}
return right;
}
}