题目
34 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:你可以设计并实现时间复杂度为O(\log n)的算法解决此问题吗?
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
思路
寻找target在数组里的左右边界,有如下三种情况:
- target 在 nums[0] ~ nums[n-1] 中,nums 中存在 target。例如 nums = [5,7,7,8,8,10],target = 8,返回 [3,4]。
 - target 在 nums[0] ~ nums[n-1] 中,nums 中不存在 target。例如 nums = [5,7,7,8,8,10],target = 6,返回 [-1,-1]。
 - target < nums[0] 或者 target > nums[n-1]。例如 nums = [5,7,7,8,8,10], target = 4,返回 [-1,-1]。
 
专注于寻找右区间,然后专注于寻找左区间,左右根据左右区间做最后判断。不要上来就想如果一起寻找左右区间,搞着搞着就会顾此失彼,绕进去拔不出来了.
//二分查找左右边界/*1.target比数组里所有元素都小;2.target比数组里所有元素都大;3.target在数组元素之间,但是没有值和target相等的元素;4.能够找到和target相等的元素,且唯一;5.能够找到和target相等的元素,但不唯一;*/class Solution {public:vector<int> searchRange(vector<int>& nums, int target) {int leftborder = LeftBorder(nums, target);int rightborder = RightBorder(nums, target);//情况1和情况2和情况3if(leftborder==-2 || rightborder==-2) return {-1,-1};//情况4和5else return {leftborder,rightborder};}private://寻找左边界(包括target元素本身)int LeftBorder(vector<int>& nums, int target){int left = 0; //上限int right = nums.size()-1; //下限int leftborder = -2; //初始化左边界值为-2while(left<=right){int mid = left+((right-left)/2); //中间//等于的时候也缩小下限,往目标元素值左边逼近if(nums[mid]==target){leftborder = mid; //不断更新边界值right = mid-1; //接着缩小范围,看看它左边还有没有等于target的元素}else if(nums[mid]>target){right = mid-1;}else left = mid+1;}//最后返回左边界的索引return leftborder;}//寻找右边界(包括target元素本身)int RightBorder(vector<int>& nums, int target){int left = 0; //上限int right = nums.size()-1; //下限int rightborder = -2; //初始化右边界值为-2while(left<=right){int mid = left+((right-left)/2); //中间//等于的时候也缩小下限,往右边逼近if(nums[mid]==target){rightborder = mid; //不断更新边界值left = mid+1; //接着缩小范围,看看它右边还有没有等于target的元素}else if(nums[mid]<=target){left = mid+1;}else right = mid-1;}//最后返回右边界的索引return rightborder;}};
普通二分查找是,当 nums[mid] == target 时,直接返回 mid,而在本题中,则是要继续向左或向右查找,看是否还有和target相等的数组元素。
