题目1 在排序数组中查找一个数字出现的次数
输入: nums = [5,7,7,8,8,10], target = 8
注意为有序数组
输出: 2
- 分析 :遍历的话很简单,但是时间复杂度O(n),题目看上去很简单,但是真正的降低时间复杂度也需要用到一些算法的知识。由有序数组可知,我们可以得到第一次出现这个数字与最后一次出现这个数字的索引,从而相减得到该数字出现的次数。
- 容易忽略的点 :数组本身为空数组;数组不为空,但是并不包含目标数字;
- 关于此题用二分查找的一点小trick:用两个条件判断即可。指针最好为right=mid, l=mid+1; 空间用闭区间[0,len(nums)-1]
- 直接贴代码吧:
class Solution:
def search(self, nums: List[int], target: int) -> int:
if len(nums):
return 0
l=0
r=len(nums)-1 #l和r想找到该数字最后一次出现的位置
s=0
e=len(nums)-1 #s和e想找到该数字第一次出现的位置
while(l<r): #当l=r时跳出循环
mid=(l+r)//2
if target<nums[mid+1]:
r=mid #r=mid, l=mid+1保证不会陷入死循环
if target>=nums[mid+1]:
l=mid+1
while(s<e):
m=(s+e)//2
if target<=nums[m]:
e=m
if target>nums[m]:
s=m+1
if nums[s]==target and nums[l]==target:
#为了考虑数组为空以及数组并不包含目标数字的情况
return l-s+1
else:
return 0
题目2 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
- 分析: 容易忽略的点 :数组本身为空数组;数组不为空,但是并不包含目标数字;
- 关于此题用二分查找的一点小trick:用两个条件判断即可。指针最好为right=mid, l=mid+1; 空间用闭区间[0,len(nums)-1]
- 直接贴代码吧:
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
if len(nums)<1:
return[-1,-1]
l=0
r=len(nums)-1
s=0
e=len(nums)-1
while(l<r):
mid=(l+r)//2
if target<nums[mid+1]:
r=mid
if target>=nums[mid+1]:
l=mid+1
while(s<e):
m=(s+e)//2
if target<=nums[m]:
e=m
if target>nums[m]:
s=m+1
if nums[s]==target and nums[l]==target:
return [s,l]
else:
return [-1,-1]
以下是根据两个题目的总结
下面总结一下查找有序数组中重复元素第一次和最后一次出现位置的代码
下面是查找元素第一次出现的位置
def search(nums:list, target: int) -> int:
if len(nums):
return -1
s=0
e=len(nums)-1
while(s<e):
m=(s+e)//2
if target<=nums[m]: #查找第一次出现的位置,要不停的往左缩小查找范围
e=m
if target>nums[m]:
s=m+1
if nums[s]==target :
return s
else:
return -1
nums=[2,3,5,6,7]
target=6
search(nums,target)
下面为查找最后一次出现的位置,由于向下取整的特性,有些特殊
def search(nums: list, target: int) -> int:
if len(nums) <1:
return -1
l=0
r=len(nums) -1 #l和r想找到该数字最后一次出现的位置
while(l<r): #当l=r时跳出循环
mid=(l+r)//2
if target<nums[mid+1]:#此处比较Mid+1
r=mid #r=mid, l=mid+1保证不会陷入死循环
if target>=nums[mid+1]:
l=mid+1
#因为2+3或3+4对2取整只会得到2和3 ,而不会变成3和4,所以这里我们采用mid+1。即取整是向下取整,所以要想查找最后一次出现的位置,需要向右缩小查找范围,不能用向下取整,因为借助[mid+1]更新l
if nums[l]==target:
return l
else:
return -1
#测试用例
nums=[0,1,2,3,3]
target=3
search(nums,target)
nums=[0,1]
target=0
search(nums,target)