📌  相关文章
📜  查找排序数组中元素的第一个和最后一个位置(1)

📅  最后修改于: 2023-12-03 15:40:24.320000             🧑  作者: Mango

查找排序数组中元素的第一个和最后一个位置

在排序数组中查找目标元素的第一个和最后一个位置,是一道经典面试题目,同时也是算法练习的重要题目之一。在本文中,我们将介绍一些解决这个问题的方法,并给出对应的代码实现。

问题描述

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你可以设计并实现时间复杂度为 O(log n) 的算法来解决此问题吗?

解决方法
方法一:暴力查找

暴力查找的方法是最为简单的一种,直接模拟元素查找的过程,找到第一个等于目标值的元素位置和最后一个等于目标值的元素位置。这种方法时间复杂度为 O(n),不满足题目要求,只能作为参考。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        first, last = -1, -1
        for i, num in enumerate(nums):
            if num == target:
                if first == -1:
                    first = i
                last = i
        return [first, last]
方法二:二分查找

由于数组是已经排序的,因此可以用二分查找快速定位目标值的第一个位置和最后一个位置。

具体地,查找第一个等于目标值的元素位置时,如果当前中间元素值大于等于目标值,那么目标值一定出现在数组左侧;否则目标值出现在数组右侧。查找最后一个等于目标值的元素位置时,同理。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def searchFirst(nums, target):
            n = len(nums)
            left, right = 0, n-1
            while left <= right:
                mid = (left + right) // 2
                if nums[mid] >= target:
                    right = mid - 1
                else:
                    left = mid + 1
            if left < n and nums[left] == target:
                return left
            else:
                return -1
        
        def searchLast(nums, target):
            n = len(nums)
            left, right = 0, n-1
            while left <= right:
                mid = (left + right) // 2
                if nums[mid] > target:
                    right = mid - 1
                else:
                    left = mid + 1
            if right >= 0 and nums[right] == target:
                return right
            else:
                return -1
        
        return [searchFirst(nums, target), searchLast(nums, target)]
方法三:标准库函数

Python 标准库中的 bisect 模块提供了二分查找的实现,可以用于查找目标值的第一个位置和最后一个位置。

具体地,通过 bisect_left 函数查找第一个等于目标值的元素位置,通过 bisect_right 函数查找最后一个小于等于目标值的元素位置,然后对位置进行判断即可。

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        import bisect
        first = bisect.bisect_left(nums, target)
        last = bisect.bisect_right(nums, target) - 1
        if first < len(nums) and nums[first] == target:
            return [first, last]
        else:
            return [-1, -1]
总结

在本文中,我们介绍了三种查找排序数组中元素的第一个和最后一个位置的方法。其中,暴力查找虽然简单但时间复杂度高,不建议使用。二分查找是常见的做法,时间复杂度为 O(log n)。标准库函数则可以快速实现算法,不过需要注意边界情况的处理。