中等难度的题目,
第一想法其实很简单,就是循环遍历,记录数组
中等于
的元素的下标,然后直接返回第一个和最后一个下标。
if target not in nums:
这是在判断
是否在数组
里,如果不存在就直接返回
。
代码:
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
if target not in nums:
return [-1, -1]
res = []
for i in range(len(nums)):
if nums[i] == target:
res.append(i)
return [res[0], res[-1]]
但是显然这段代码的时间复杂度并不是
。于是,采用二分思想解题。
关于二分查找的算法详解,可以看这篇文章:
力扣leetcode-cn.com在有序数组中查找元素肯定使用二分法,二分法的核心思想是“夹逼法”或“排除法”,是“减而治之”算法思想的体现。
- 尽最大可能排除不符合题意的元素,在每一轮循环中不断减少候选区间的范围,直到候选区间收缩成 1 个数。
- 因为数组中很可能不存在目标值,因此在第 1 步使用“排除法”最后剩下的这个数,再判断一下它是否等于
即可。
对于这个问题,我们其实可以拆分成两个问题,分别来解决。
- 开始位置:找到等于
的第一个元素索引,如果找不到等于的数,则返回-1。如果小于,肯定不是解,此时。
- 结束位置:找到等于
的最后一个个元素索引,如果找不到等于的数,则返回-1。如果大于,肯定不是解,此时。
下面给出的参考代码:
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
size = len(nums)
if size == 0:
return [-1, -1]
num1 = self.__lower_bound(nums, target)
if num1 == -1:
return [-1, -1]
num2 = self.__upper_bound(nums, target)
return [num1, num2]
def __lower_bound(self, nums, target):
left, right = 0, len(nums) - 1
while left < right:
# mid = left + (right - left) // 2
mid = (left + right) >> 1
if nums[mid] < target:
left = mid + 1
else:
right = mid
if nums[left] != target:
return -1
return left
def __upper_bound(self, nums, target):
left, right = 0, len(nums) - 1
while left < right:
# mid = left + (right - left + 1) // 2
mid = (left + right + 1) >> 1
if nums[mid] > target:
right = mid - 1
else:
left = mid
if nums[left] != target:
return -1
return left
代码中我把
mid = left + (right - left) // 2
以及
mid = left + (right - left) // 2
改成
mid = (left + right) >> 1
和
mid = (left + right + 1) >> 1
的原因是参照这篇文章:
力扣leetcode-cn.com另外,这篇文章的作者也写了一篇《十分好用的二分查找法模板》,可以看一下。
力扣leetcode-cn.com