本文最后更新于:2023年3月19日 晚上
Lt34. 在排序数组中查找元素的第一个和最后一个位置,二分算法
难度中等 677 收藏分享切换为英文接收动态反馈
给定一个按照升序排列的整数数组 nums
,和一个目标值 target
。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target
,返回 [-1, -1]
。
进阶:
- 你可以设计并实现时间复杂度为
O(log n)
的算法解决此问题吗?
示例 1:
1 2
| 输入:nums = , target = 8 输出:
|
示例 2:
1 2
| 输入:nums = , target = 6 输出:
|
示例 3:
1 2
| 输入:nums = , target = 0 输出:
|
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
是一个非递减数组
-109 <= target <= 109
思路
普通遍历
使用两个额外变量,记录第一次出现下标,遍历元素,每出现一次就更新一次最后出现的下标。时间复杂度 O(n)
二分查找
先使用二分查找出第一个等于目标值的元素的下标,再分别再左右两边二分算法,缩小窗口大小,直到又找到一个等于目标值的元素:如果是左边就不断令左窗口边界减一直到边界值剑一的元素为非目标值元素,如果是左边就不断令右窗口边界加一直到边界值加一的元素为非目标值元素。左右窗口边界的值即为所求目标。
解答
普通遍历
不写了,很容易就可以想到,此题为复习题,可以搜索查看之前的博文。
二分查找
执行用时超过 99%
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
|
var searchRange = function (nums, target) { let res = [-1, -1]; let start = 0, end = nums.length - 1; let index = -1; while (start <= end) { let mid = parseInt((start + end) / 2); if (nums[mid] < target) start = mid + 1; else if (nums[mid] > target) end = mid - 1; else { index = mid; break; } } if (index === -1) return res; start = 0; end = index; while (start <= end) { start = parseInt((start + end) / 2); if (nums[start] < target) start++; else { while (start > 0 && nums[start - 1] === target) start--; res[0] = start; break; } } start = index; end = nums.length - 1; while (start <= end) { end = parseInt((start + end) / 2); if (nums[end] > target) end--; else { while (end < nums.length - 1 && nums[end + 1] === target) end++; res[1] = end; break; } } return res; };
|