本文最后更新于:2023年3月19日 晚上
L34. 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums
,和一个目标值 target
。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]
。
示例 1:
1 2
| 输入: nums = , target = 8 输出:
|
示例 2:
1 2
| 输入: nums = , target = 6 输出:
|
思路
二分搜索,首先用二分法查出第一个和 target 相等的元素的下标。如果 index 仍然等于-1 则不存在该元素,返回[-1,-1]。
分别从该元素的左边和右边查到开始和结尾,看 target 元素出现的第一次和最后一次。有以下逻辑:
第一次二分查找左半边,查找第一个 target 元素,设置左右指针分别为 l 和 index。
- 如果最左边的元素即 l 指向的元素就为 target,将 first 设为 l
- 计算 middle,如果 middle 等于 target,令 r–,继续判断右边下一个是否和 target 相等
- 如果 middle 指向的数小于目标值,令 l=middle+1,继续二分查找
第二次二分查找右半边,查最后一个 target 元素,逻辑类似。
解答
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
|
var searchRange = function (nums, target) { let l = 0, r = nums.length - 1, index = -1; while (l <= r) { let middle = parseInt((l + r) / 2); if (nums[middle] === target) { index = middle; break; } else if (nums[middle] < target) l = middle + 1; else r = middle - 1; }
if (index === -1) return [-1, -1]; let first = -1, last = -1; (l = 0), (r = index); while (l <= r) { let middle = parseInt((l + r) / 2); if (nums[middle] === target) { if (l === 0 && nums[l] === target) { first = l; break; } else if (middle > 0 && nums[middle - 1] !== target) { first = middle; break; } r--; } else if (nums[middle] < target) l = middle + 1; } (l = index), (r = nums.length - 1); while (l <= r) { let middle = parseInt((l + r) / 2); if (nums[middle] === target) { if (r === nums.length - 1 && nums[r] === target) { last = r; break; } else if (middle < nums.length - 1 && nums[middle + 1] !== target) { last = middle; break; } l++; } else if (nums[middle] > target) r = middle - 1; } return [first, last]; };
|