力扣刷题Python笔记:在排序数组中查找元素的第一个和最后一个位置

题目

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

你的算法时间复杂度必须是 O(log n) 级别。

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

力扣刷题Python笔记:在排序数组中查找元素的第一个和最后一个位置_第1张图片
来源:力扣(LeetCode)

python解法

这个题的暴力解法很简单,顺序遍历一遍数组nums找最小下标,逆序再遍历一遍找最大下标。但是这样做的时间复杂度为O(n),而题目要求“时间复杂度必须是 O(log n) 级别”,因此这道题我们同样得用二分查找。

二分解法

不同于上一道题的是,我们这次要寻找的是元素下标的最大最小位置,即不确定元素在数组中的个数,因此这道题不像上题那样单纯地判断元素与目标值是否相等就行了。

具体的解题思路如下:
①创建左右两个指针 left 和 right,初始位置分别为 0 和 len(nums)。
②首先寻找元素的第一个位置对应的坐标:令 mid 取 left 和 right 的中间位置,当 mid 对应的元素大于或等于目标元素时,说明元素的最小下标肯定不大于当前 mid,那么将 right 移动到 mid 位置;当 mid 对应的元素小于目标元素时,说明元素的最小下标肯定在当前 mid 的右侧,那么将 left 移动到mid+1 的位置。
③更新 mid,重复第②步。当左右指针重合时,停止循环,返回 left 作为元素的位置最小下标 left_index。
④如果 left_index 等于数组长度或者对应的元素不等于目标元素,说明目标元素不存在数组中,直接返回 [-1, -1]。
⑤寻找元素的最后一个位置对应坐标的方法与步骤②相同,因此我们可以将步骤②对应的代码封装成函数重用,为了区分我们调用函数时是寻找最小下标还是最大下标,我们加了一个参数 is_min

代码如下:

def searchRange(self, nums: List[int], target: int) -> List[int]:
    def search_left_or_right(nums, target, is_min):
        left = 0
        right = len(nums)

        while left < right:
            mid = (left + right) // 2
            if nums[mid] > target or (is_min and target == nums[mid]):
                right = mid
            else:
                left = mid + 1

        return left
    
    left_idx = search_left_or_right(nums, target, True)

    if left_idx == len(nums) or nums[left_idx] != target:
        return [-1, -1]
    right_idx = search_left_or_right(nums, target, False)-1

    return [left_idx, right_idx]

你可能感兴趣的:(力扣python刷题,算法)