Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述:
给定一个按照升序排列的整数数组 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 <= 10 的 5 次方
-10 的 9次方 <= nums[i] <= 10 的 9次方
nums 是一个非递减数组
-10 的 9次方 <= target <= 10 的 9次方
思路分析:
方法1: 二分查找目标值的位置,然后从该位置分别向前后查找不等于目标值的位置。
方法2: 单次循环,找到目标值的第一个位置,然后再从后面找到第一个不是目标值的位置。
AC 代码:
golang :
- 二分查找
// 在排序数组中查找元素的第一个和最后一个位置
func searchRange(nums []int, target int) []int {
min, max := -1, -1
n := BinarySearchRecursive(nums, target, 0, len(nums)-1)
if n >= 0 {
// 二分查找位置向前
for i := n; i >= 0; i-- {
if nums[i] == target {
min = i
}
if nums[i] != target {
break
}
}
// 二分查找位置向后
for i := n; i < len(nums); i++ {
if nums[i] == target {
max = i
}
if nums[i] != target {
break
}
}
}
return []int{min, max}
}
// 递归二分查找
func BinarySearchRecursive(slice []int, value int, low int, high int) int {
if low > high {
return -1
}
// 中间位置等于 低位位置 + (高位位置-低位位置)/2
mid := low + (high-low)/2
// 找到目标值,返回位置
if slice[mid] == value {
return mid
}
// 当前值小于目标值,则低位位置 改为 中间位置 + 1
if slice[mid] < value {
low = mid + 1
}
// 当前值大于目标值,则高位位置 改为 中间位置 - 1
if slice[mid] > value {
high = mid - 1
}
return BinarySearchRecursive(slice, value, low, high)
}
- 单次循环
// 在排序数组中查找元素的第一个和最后一个位置
func searchRange(nums []int, target int) []int {
min, max := -1, -1
for i, v := range nums {
// 目标值的元素
if v == target {
// 第一个目标值的元素
if min == -1 {
min = i
}
max = i
}
// 最后一个目标值后面的元素,之后的元素不需要再比较
if max != -1 && v != target {
break
}
}
return []int{min, max}
}
总结:
二分查找到目标值的位置后,还是需要分别向前后再找,感觉极端情况下效率也不会太高。
应该还有更优解。