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

Posted 炫云云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了34. 在排序数组中查找元素的第一个和最后一个位置相关的知识,希望对你有一定的参考价值。

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]

二分查找

意境级讲解二分查找算法、python

思路与算法 : 二分查找

直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见 target \\textit{target} target 的下标,但这个方法的时间复杂度为 O ( n ) O(n) O(n)​ ,没有利用到数组升序排列的条件。

查找最接近且小于 target 的元素

while (l <= r):
    mid = l + (r-l)//2;
    if(target > nums[mid])
        l = mid + 1;
    else  #target <= nums[mid]
        r = mid - 1;

# 循环结束后,r 指向最接近且小于 target 的元素的位置
# (若 r 下标越界,则表示不存在); l = r + 1

查找最接近且大于 target 的元素

while(l <= r):
    mid = l + (r-l)//2;
    if(target >= nums[mid])
        l = mid + 1;
    else
        r = mid - 1;

#循环结束后,l 指向最接近且大于 target 的元素的位置
#(若 l 下标越界,则表示不存在); r = l - 1

由于数组已经排序,因此整个数组是单调递增的,我们可以利用二分法来加速查找的过程。

考虑 target \\textit{target} target 开始和结束位置,其实我们要找的就是数组中「第一个等于 target \\textit{target} target 的位置」(记为 leftIdx \\textit{leftIdx} leftIdx )和「第一个大于 target \\textit{target} target 的位置减一」(记为 rightIdx \\textit{rightIdx} rightIdx)。

定义一个二分查找,寻找 leftIdx \\textit{leftIdx} leftIdx 即为在数组中寻找第一个等于 target \\textit{target} target 的下标,寻找 rightIdx \\textit{rightIdx} rightIdx 即为在数组中寻找第一个大于 target \\textit{target} target 的下标,然后将下标减一,即为最后一个位置。

最后,因为 target \\textit{target} target 可能不存在数组中,因此我们需要重新校验我们得到的两个下标 leftIdx \\textit{leftIdx} leftIdx rightIdx \\textit{rightIdx} rightIdx,看是否符合条件,如果符合条件就返回 [ leftIdx , rightIdx ] [\\textit{leftIdx},\\textit{rightIdx}] [leftIdx,rightIdx] ,不符合就返回 [ − 1 , − 1 ] [-1,-1] [1,1]

class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        def binarySearch(nums, target):
            left =0
            right = len(nums) -1
            while left<=right:
                mid = left+(right-left)//2
                if nums[mid]< target : # 应该继续向右边找,搜索区间变为 [mid+1, right]
                    left = mid +1
                else:
                    right = mid-1  #应该继续向左边找 ,搜索区间变为 [left, mid  -1] ,
                    #[5,7,7,8,8,10],target=8. 
                    # 寻找第一个满足条件的点, 即使得right在满足target的数的最左边,即寻找8的左边界
            return left
        leftIdx = binarySearch(nums, target)
        rightIdx = binarySearch(nums, target+1)-1

        if leftIdx== len(nums) or nums[leftIdx] != target:
            return [-1,-1]
        else:
            return [leftIdx, rightIdx]

参考

Krahets - 力扣(LeetCode) (leetcode-cn.com)

以上是关于34. 在排序数组中查找元素的第一个和最后一个位置的主要内容,如果未能解决你的问题,请参考以下文章

java刷题--34在排序数组中查找元素的第一个和最后一个位置

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

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

算法leetcode|34. 在排序数组中查找元素的第一个和最后一个位置(rust重拳出击)

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

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