Leetcode---34.排序数组中元素的第一个位置和最后一个位置
因为昨天新学的二分法,所以今天决定试一下,这道题,刚开始的时候,可以看出这道题是一个递增数列,也就特别符合二分法的使用条件之一,另一个条件是没有重复元素,但是显然是有的,那么,我们怎么做比较好呢,就选择用两个二分法来找到左右边界吧
疑问一:为什么是找到左右边界呢?
因为是一个递增数列,如果我遍历出的左右边界一致,那么左右边界内部的数一定都相等,这也就是为什么要找左右边界。
疑问二:左右边界怎么使用二分法啊
下面我用图来简单说明一下这个思路过程。
最开始是一个这样的状态,会在这个状态中找到mid,也就是中间值,(right+left)/2=2,也就是元素为6的位置,这个时候,如果我的target,也就是目标值为6的话,就已经定位到了一个值,但是此时在程序中,我们并不知道找到的这个6是否是左边界的第一个值(因为用例并不是一个确定的,在我们不清楚用例的情况下,是看不到返回的是第几个值),那么我们就需要去判断一下,它前面是否还有值或者后面是否还值(左边界值需要对前边进行判断,右边界值需要对后边进行判断),也就是用nums[mid] !=nums[mid-1]来做判断。
左边界:若已经是第一个值,那么直接返回,当作左边界值即可,若不是第一个值,假设如下图
那么我们要得到左边界,就需要将right左移,不断地缩小区间,也就是right=mid-1,这样的话,直接就将后边的重复值忽略掉了。
具体代码如下:
class Solution {
public int[] searchRange(int[] nums, int target) {
int first = searchFirst(nums,target);
int last = searchLast(nums,target);
return new int[]{first,last};
}
public int searchFirst(int[] nums,int target){
int left = 0;
int right = nums.length-1;
while(left<=right){
int mid =left + (right-left)/2;
if(nums[mid]>target){
right = mid-1;
}else if(nums[mid]<target){
left = mid+1;
}else{
if(mid == 0 || nums[mid] != nums[mid-1]){
return mid;
}else{
right = mid-1;
}
}
}
return -1;
}
public int searchLast(int[] nums,int target){
int left = 0;
int right = nums.length-1;
while(left<=right){
int mid =left + (right-left)/2;
if(nums[mid]>target){
right = mid-1;
}else if(nums[mid]<target){
left = mid+1;
}else{
if(mid == nums.length-1|| nums[mid] != nums[mid+1]){
return mid;
}else{
left = mid+1;
}
}
}
return -1;
}
}
(本文的思路出处:二分法的思想来自于代码随想录的carl哥,这道题的解题思想来自于b站的忍者算法,我只是将一些,我当时思考有问题的地方,复现了出来)