[LeetCode][golang] 34. 在排序数组中查找元素的第一个和最后一个位置

257 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述:

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 <= 10 的 5 次方
-10 的 9次方 <= nums[i] <= 10 的 9次方
nums 是一个非递减数组
-10 的 9次方 <= target <= 10 的 9次方

思路分析:

方法1: 二分查找目标值的位置,然后从该位置分别向前后查找不等于目标值的位置。

方法2: 单次循环,找到目标值的第一个位置,然后再从后面找到第一个不是目标值的位置。

AC 代码:

golang :

  1. 二分查找
// 在排序数组中查找元素的第一个和最后一个位置
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)
}
  1. 单次循环
// 在排序数组中查找元素的第一个和最后一个位置
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}
}

总结:

二分查找到目标值的位置后,还是需要分别向前后再找,感觉极端情况下效率也不会太高。
应该还有更优解。