给定一个升序排列的数组,以及一个整数,查找这个整数在数组中出现的起始、终止下标。没找到就返回 [-1,-1]。要求O(logn)时间复杂度。
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
思路:
运用二分查找,当找到与目标相等的下标时,停下来,分别找左边的起始点,右边的终止点。而左边要求: nums[mid] == target && nums[mid-1] != target,或者 mid = =left;而右边终止点要求:nums[mid] == target &&nums[mid+1] != target, 或者 mid==right.所以,另外写一个函数,用startOrEnd = 1 / -1来区别是找起始点还是终止点。
当startOrEnd = 1 时, mid - startOrEnd = mid-1;当 = -1时,mid - startOrEnd = mid+1.
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int n = nums.size(), l = 0, r = n - 1, mid = 0; int start = -1, end = -1; while (l <= r) { mid = (l + r) / 2; if (nums[mid] == target) { start = searchPosition(nums, l, mid, target, 1);//起始点 end = searchPosition(nums, mid, r, target, -1);//终止点 return { start,end }; } else if (nums[mid] > target) r = mid - 1; else l = mid + 1; } return { start,end }; } int searchPosition(vector<int>& nums, int left, int right, int target, int startOrEnd) { while (left <= right) { int mid = (left + right) / 2; if (nums[mid] == target) { if (mid == left && startOrEnd == 1) return mid;//左边mid = left else if (mid == right && startOrEnd == -1) return mid;//右边mid = right if (nums[mid - startOrEnd] != target) return mid; if (startOrEnd == 1) right = mid - 1;//否则,继续循环 else left = mid + 1; } else if (nums[mid] > target) right = mid - 1; else left = mid + 1; } return -1; } };
Java 版:
• 对于已经排好序的数组,首先想到的就是二分查找;
• 当找到与目标值相等的下标时,停下来,分别找左边的起始点,右边的终止点;
• 左指针要求: nums[mid] == target && nums[mid-1] != target;
• 右指针要求:nums[mid] == target && nums[mid+1] != target。
• 所以,分别用两个函数,得到左指针、右指针的位置。
class Solution { public int[] searchRange(int[] nums, int target) { int l = serchLeftIndx(nums, target); int r = serchRightIndx(nums, target); if(l > r) return new int[]{-1, -1}; //没有找到结果 return new int[]{l,r}; } public int serchLeftIndx(int[] nums, int target){ //得到左指针位置 int mid = 0, l = 0, r = nums.length - 1; while(l <= r){ mid = (l + r) / 2; if(nums[mid] >= target) r = mid - 1; else l = mid + 1; } return l; } public int serchRightIndx(int[] nums, int target){ //得到右指针位置 int mid = 0, l = 0, r = nums.length - 1; while( l <= r){ mid = (l + r) / 2; if(nums[mid] <= target) l = mid + 1; else r = mid - 1; } return l - 1; } }