34. 在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组 nums
,和一个目标值 target
。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target
,返回 [-1, -1]
。
你必须设计并实现时间复杂度为 O(log n)
的算法解决此问题。
示例 1:
输入:nums = [5,7,7,8,8,10]
, target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10]
, target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0 输出:[-1,-1]
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
是一个非递减数组-109 <= target <= 109
相似题目
原站题解
javascript 解法, 执行用时: 63 ms, 内存消耗: 50 MB, 提交时间: 2024-04-23 14:39:00
// lowerBound 返回最小的满足 nums[i] >= target 的 i // 如果数组为空,或者所有数都 < target,则返回 nums.length // 要求 nums 是非递减的,即 nums[i] <= nums[i + 1] // 闭区间写法 var lowerBound = function (nums, target) { let left = 0, right = nums.length - 1; // 闭区间 [left, right] while (left <= right) { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right+1] >= target const mid = Math.floor((left + right) / 2); if (nums[mid] < target) { left = mid + 1; // 范围缩小到 [mid+1, right] } else { right = mid - 1; // 范围缩小到 [left, mid-1] } } return left; } // 左闭右开区间写法 var lowerBound2 = function (nums, target) { let left = 0, right = nums.length; // 左闭右开区间 [left, right) while (left < right) { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right] >= target const mid = Math.floor((left + right) / 2); if (nums[mid] < target) { left = mid + 1; // 范围缩小到 [mid+1, right) } else { right = mid; // 范围缩小到 [left, mid) } } return left; // 返回 left 还是 right 都行,因为循环结束后 left == right } // 开区间写法 var lowerBound3 = function (nums, target) { let left = -1, right = nums.length; // 开区间 (left, right) while (left + 1 < right) { // 区间不为空 // 循环不变量: // nums[left] < target // nums[right] >= target const mid = Math.floor((left + right) / 2); if (nums[mid] < target) { left = mid; // 范围缩小到 (mid, right) } else { right = mid; // 范围缩小到 (left, mid) } } return right; } var searchRange = function (nums, target) { const start = lowerBound(nums, target); // 选择其中一种写法即可 if (start === nums.length || nums[start] !== target) { return [-1, -1]; // nums 中没有 target } // 如果 start 存在,那么 end 必定存在 const end = lowerBound(nums, target + 1) - 1; return [start, end]; };
golang 解法, 执行用时: 4 ms, 内存消耗: 4.4 MB, 提交时间: 2024-04-23 14:38:42
// lowerBound 返回最小的满足 nums[i] >= target 的 i // 如果数组为空,或者所有数都 < target,则返回 len(nums) // 要求 nums 是非递减的,即 nums[i] <= nums[i + 1] // 闭区间写法 func lowerBound(nums []int, target int) int { left, right := 0, len(nums)-1 // 闭区间 [left, right] for left <= right { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right+1] >= target mid := left + (right-left)/2 if nums[mid] < target { left = mid + 1 // 范围缩小到 [mid+1, right] } else { right = mid - 1 // 范围缩小到 [left, mid-1] } } return left } // 左闭右开区间写法 func lowerBound2(nums []int, target int) int { left, right := 0, len(nums) // 左闭右开区间 [left, right) for left < right { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right] >= target mid := left + (right-left)/2 if nums[mid] < target { left = mid + 1 // 范围缩小到 [mid+1, right) } else { right = mid // 范围缩小到 [left, mid) } } return left // 返回 left 还是 right 都行,因为循环结束后 left == right } // 开区间写法 func lowerBound3(nums []int, target int) int { left, right := -1, len(nums) // 开区间 (left, right) for left+1 < right { // 区间不为空 // 循环不变量: // nums[left] < target // nums[right] >= target mid := left + (right-left)/2 if nums[mid] < target { left = mid // 范围缩小到 (mid, right) } else { right = mid // 范围缩小到 (left, mid) } } return right } func searchRange(nums []int, target int) []int { start := lowerBound(nums, target) // 使用其中一种写法即可 if start == len(nums) || nums[start] != target { return []int{-1, -1} // nums 中没有 target } // 如果 start 存在,那么 end 必定存在 end := lowerBound(nums, target+1) - 1 return []int{start, end} }
cpp 解法, 执行用时: 6 ms, 内存消耗: 15.7 MB, 提交时间: 2024-04-23 14:38:26
class Solution { // lower_bound 返回最小的满足 nums[i] >= target 的 i // 如果数组为空,或者所有数都 < target,则返回 nums.size() // 要求 nums 是非递减的,即 nums[i] <= nums[i + 1] // 闭区间写法 int lower_bound(vector<int> &nums, int target) { int left = 0, right = (int) nums.size() - 1; // 闭区间 [left, right] while (left <= right) { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right+1] >= target int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; // 范围缩小到 [mid+1, right] } else { right = mid - 1; // 范围缩小到 [left, mid-1] } } return left; } // 左闭右开区间写法 int lower_bound2(vector<int> &nums, int target) { int left = 0, right = nums.size(); // 左闭右开区间 [left, right) while (left < right) { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right] >= target int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; // 范围缩小到 [mid+1, right) } else { right = mid; // 范围缩小到 [left, mid) } } return left; // 返回 left 还是 right 都行,因为循环结束后 left == right } // 开区间写法 int lower_bound3(vector<int> &nums, int target) { int left = -1, right = nums.size(); // 开区间 (left, right) while (left + 1 < right) { // 区间不为空 // 循环不变量: // nums[left] < target // nums[right] >= target int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid; // 范围缩小到 (mid, right) } else { right = mid; // 范围缩小到 (left, mid) } // 也可以这样写 // (nums[mid] < target ? left : right) = mid; } return right; } public: vector<int> searchRange(vector<int> &nums, int target) { int start = lower_bound(nums, target); // 使用其中一种写法即可 if (start == nums.size() || nums[start] != target) { return {-1, -1}; // nums 中没有 target } // 如果 start 存在,那么 end 必定存在 int end = lower_bound(nums, target + 1) - 1; return {start, end}; } };
java 解法, 执行用时: 0 ms, 内存消耗: 45 MB, 提交时间: 2024-04-23 14:38:11
class Solution { public int[] searchRange(int[] nums, int target) { int start = lowerBound(nums, target); // 选择其中一种写法即可 if (start == nums.length || nums[start] != target) { return new int[]{-1, -1}; // nums 中没有 target } // 如果 start 存在,那么 end 必定存在 int end = lowerBound(nums, target + 1) - 1; return new int[]{start, end}; } // lowerBound 返回最小的满足 nums[i] >= target 的 i // 如果数组为空,或者所有数都 < target,则返回 nums.length // 要求 nums 是非递减的,即 nums[i] <= nums[i + 1] // 闭区间写法 private int lowerBound(int[] nums, int target) { int left = 0, right = nums.length - 1; // 闭区间 [left, right] while (left <= right) { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right+1] >= target int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; // 范围缩小到 [mid+1, right] } else { right = mid - 1; // 范围缩小到 [left, mid-1] } } return left; } // 左闭右开区间写法 private int lowerBound2(int[] nums, int target) { int left = 0, right = nums.length; // 左闭右开区间 [left, right) while (left < right) { // 区间不为空 // 循环不变量: // nums[left-1] < target // nums[right] >= target int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid + 1; // 范围缩小到 [mid+1, right) } else { right = mid; // 范围缩小到 [left, mid) } } return left; // 返回 left 还是 right 都行,因为循环结束后 left == right } // 开区间写法 private int lowerBound3(int[] nums, int target) { int left = -1, right = nums.length; // 开区间 (left, right) while (left + 1 < right) { // 区间不为空 // 循环不变量: // nums[left] < target // nums[right] >= target int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid; // 范围缩小到 (mid, right) } else { right = mid; // 范围缩小到 (left, mid) } } return right; } }
python3 解法, 执行用时: 42 ms, 内存消耗: 17.9 MB, 提交时间: 2024-04-23 14:37:54
# lower_bound 返回最小的满足 nums[i] >= target 的 i # 如果数组为空,或者所有数都 < target,则返回 len(nums) # 要求 nums 是非递减的,即 nums[i] <= nums[i + 1] # 闭区间写法 def lower_bound(nums: List[int], target: int) -> int: left, right = 0, len(nums) - 1 # 闭区间 [left, right] while left <= right: # 区间不为空 # 循环不变量: # nums[left-1] < target # nums[right+1] >= target mid = (left + right) // 2 if nums[mid] < target: left = mid + 1 # 范围缩小到 [mid+1, right] else: right = mid - 1 # 范围缩小到 [left, mid-1] return left # 左闭右开区间写法 def lower_bound2(nums: List[int], target: int) -> int: left = 0 right = len(nums) # 左闭右开区间 [left, right) while left < right: # 区间不为空 # 循环不变量: # nums[left-1] < target # nums[right] >= target mid = (left + right) // 2 if nums[mid] < target: left = mid + 1 # 范围缩小到 [mid+1, right) else: right = mid # 范围缩小到 [left, mid) return left # 返回 left 还是 right 都行,因为循环结束后 left == right # 开区间写法 def lower_bound3(nums: List[int], target: int) -> int: left, right = -1, len(nums) # 开区间 (left, right) while left + 1 < right: # 区间不为空 mid = (left + right) // 2 # 循环不变量: # nums[left] < target # nums[right] >= target if nums[mid] < target: left = mid # 范围缩小到 (mid, right) else: right = mid # 范围缩小到 (left, mid) return right class Solution: def searchRange(self, nums: List[int], target: int) -> List[int]: start = lower_bound(nums, target) # 选择其中一种写法即可 if start == len(nums) or nums[start] != target: return [-1, -1] # nums 中没有 target # 如果 start 存在,那么 end 必定存在 end = lower_bound(nums, target + 1) - 1 return [start, end]
javascript 解法, 执行用时: 62 ms, 内存消耗: 49.9 MB, 提交时间: 2024-04-23 14:37:01
/** * @param {number[]} nums * @param {number} target * @return {number[]} */ const binarySearch = (nums, target, lower) => { let left = 0, right = nums.length - 1, ans = nums.length; while (left <= right) { const mid = Math.floor((left + right) / 2); if (nums[mid] > target || (lower && nums[mid] >= target)) { right = mid - 1; ans = mid; } else { left = mid + 1; } } return ans; } var searchRange = function(nums, target) { let ans = [-1, -1]; const leftIdx = binarySearch(nums, target, true); const rightIdx = binarySearch(nums, target, false) - 1; if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] === target && nums[rightIdx] === target) { ans = [leftIdx, rightIdx]; } return ans; };
java 解法, 执行用时: 0 ms, 内存消耗: 44.9 MB, 提交时间: 2024-04-23 14:36:47
class Solution { public int[] searchRange(int[] nums, int target) { int leftIdx = binarySearch(nums, target, true); int rightIdx = binarySearch(nums, target, false) - 1; if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) { return new int[]{leftIdx, rightIdx}; } return new int[]{-1, -1}; } public int binarySearch(int[] nums, int target, boolean lower) { int left = 0, right = nums.length - 1, ans = nums.length; while (left <= right) { int mid = (left + right) / 2; if (nums[mid] > target || (lower && nums[mid] >= target)) { right = mid - 1; ans = mid; } else { left = mid + 1; } } return ans; } }
cpp 解法, 执行用时: 6 ms, 内存消耗: 15.8 MB, 提交时间: 2024-04-23 14:36:36
// 二分查找 class Solution { public: int binarySearch(vector<int>& nums, int target, bool lower) { int left = 0, right = (int)nums.size() - 1, ans = (int)nums.size(); while (left <= right) { int mid = (left + right) / 2; if (nums[mid] > target || (lower && nums[mid] >= target)) { right = mid - 1; ans = mid; } else { left = mid + 1; } } return ans; } vector<int> searchRange(vector<int>& nums, int target) { int leftIdx = binarySearch(nums, target, true); int rightIdx = binarySearch(nums, target, false) - 1; if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) { return vector<int>{leftIdx, rightIdx}; } return vector<int>{-1, -1}; } };
golang 解法, 执行用时: 8 ms, 内存消耗: 3.8 MB, 提交时间: 2022-08-15 10:19:36
func searchRange(nums []int, target int) []int { leftmost := sort.SearchInts(nums, target) if leftmost == len(nums) || nums[leftmost] != target { return []int{-1, -1} } rightmost := sort.SearchInts(nums, target + 1) - 1 return []int{leftmost, rightmost} }
golang 解法, 执行用时: 12 ms, 内存消耗: 3.9 MB, 提交时间: 2021-06-23 11:22:07
func searchRange(nums []int, target int) []int { start, end := sort.SearchInts(nums, target), sort.SearchInts(nums, target+1) fmt.Println(start, end) if start >= len(nums) || nums[start] != target { start = -1 } if start == -1 { end = -1 } else { end-- } return []int{start, end} }