问题描述
给定一个升序数组和一个目标数字,要求找出目标数字在数组中的最先出现的位置和最后出现的位置。找不到则输出 [-1, -1]。要求时间复杂度近似于 Olog(n)
。 题目链接:**点我**
样例输入输出
输入:nums = [5,7,7,8,8,10],target = 8
输出:[3,4]
输入:nums = [5,7,7,8,8,10],target = 6
输出:[-1,-1]
问题解法
在一个有序数组中寻找一个数出现的起始位置和结束位置,最简单的做法就是循环遍历数组,记录最先出现的问题和最后出现的位置,但是这种做法时间复杂度为 O(n)
,不满足题目的 Olog(n)
的要求,既然时间复杂度是 Olog(n)
,那很容易想到用二分法来解决,再加上数组是升序排序的,因此,可以用类似二分搜索的方式来解决。
主要思路为:先用二分查找,找到目标数,然后在左侧数组范围内,继续用二分查找找到最先出现的目标数的下标,同样在右侧数组范围内使用二分查找找到最后出现的目标数的下标,这两个下标就是目标数在数组中出现的开始位置和结束位置。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| class Solution { private int findLeftIndex(int[] nums, int start, int end) { if (nums[start] == nums[end]) { return start; } int target = nums[end]; int mid = (start + end) / 2; if (nums[mid] < target) { return findLeftIndex(nums, mid + 1, end); } return findLeftIndex(nums, start, mid); } private int findRightIndex(int[] nums, int start, int end) { if (nums[start] == nums[end]) { return end; } int target = nums[start]; int mid = (start + end + 1) / 2; if (nums[mid] > target) { return findRightIndex(nums, start, mid - 1); } return findRightIndex(nums, mid, end); } public int[] searchRange(int[] nums, int target) { int[] result = {-1, -1}; if (nums == null || nums.length == 0 || nums[0] > target) { return result; }
int i = 0; int j = nums.length - 1; int mid = (i + j) / 2; while (mid >= i && mid <= j) { if (nums[mid] > target) { j = mid - 1; mid = (i + j) / 2; } else if (nums[mid] < target) { i = mid + 1; mid = (i + j) / 2; } else { result[0] = findLeftIndex(nums, i, mid); result[1] = findRightIndex(nums, mid, j); break; } } return result; } }
|