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

代码参考:

package main

import "fmt"

func main() {
    fmt.Println(searchRange1([]int{5, 7, 7, 8, 8, 10}, 8)) // [3, 4]
    fmt.Println(searchRange2([]int{5, 7, 7, 8, 8, 10}, 8)) // [3, 4]
    fmt.Println(searchRange2([]int{1}, 1))                 // [0, 0]
}

// 直接二分查找
// O(N) // not ok
func searchRange1(nums []int, target int) []int {
    n := len(nums)
    i := binarySearch(nums, 0, n-1, target)
    if i == -1 {
        return []int{-1, -1}
    }

    // 找到后向两侧延伸
    l, r := i, i
    for j := i - 1; j >= 0; j-- {
        if nums[j] == target {
            l = j
        }
    }
    for j := i + 1; j < n; j++ {
        if nums[j] == target {
            r = j
        }
    }
    return []int{l, r}
}

// 改进的二分搜索
func searchRange2(nums []int, target int) []int {
    l := edgeBinSearch(nums, true, target)
    r := edgeBinSearch(nums, false, target)
    return []int{l, r}
}

// 普通二分搜索在匹配到 target 时直接 return
// 在本题搜索时在匹配到 target 之后依旧向边缘走当做没匹配到,注意 2 个边界条件
// O(logN) // ok
func edgeBinSearch(nums []int, leftest bool, target int) int {
    n := len(nums)
    l, r := 0, n-1
    for l <= r {
        mid := (l + r) / 2
        switch {
        case target < nums[mid]:
            r = mid - 1
        case target > nums[mid]:
            l = mid + 1
        default:
            if leftest {
                if mid == 0 || nums[mid] > nums[mid-1] { // 不再继续向左走的 2 个边界条件
                    return mid
                }
                r = mid - 1 // 继续在左侧找
            } else {
                if mid == n-1 || nums[mid] < nums[mid+1] {
                    return mid
                }
                l = mid + 1 // 继续在右侧找
            }
        }
    }
    return -1
}
最后编辑: kuteng  文档更新时间: 2021-06-05 10:16   作者:kuteng