文章目录
1:问题描述
来源:LeetCode
难度:简单
问题详情:
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
2:问题分析
2.1 时间复杂度和空间复杂度
在真正开始介绍各种算法前,先以表格形式展示各自的时间复杂度和空间复杂度,其中n nn表示数组nums
的长度。
算法 | 时间复杂度 | 空间复杂度 |
---|---|---|
暴力法 | O ( n ) O(n)O(n) | O ( 1 ) O(1)O(1) |
二分查找 | O(l o g ( n ) log(n)log(n)) | O ( 1 ) O(1)O(1) |
2.2 暴力法
2.2.1 代码
暴力法没有什么技术含量,因此直接给出代码:
def search(self, nums: List[int], target: int) -> int:
result = 0
for item in nums:
if item == target:
result += 1
return result
时间复杂度为O ( n ) O(n)O(n),空间复杂度为O ( 1 ) O(1)O(1)
2.3 二分查找
对于有序数组的搜索问题,自然需要考虑二分查找
。
- 我们首先使用二分查找找到
target
最先出现的索引left
; - 然后使用二分查找找到
target
最后出现的索引right
; - 然后返回
right-left+1
即可。
2.3.1 二分查找第一次出现的索引
def findFirstElement(nums, target):
"""target第一次出现的位置"""
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) // 2
# 如果<, 则表示[left,mid]中没有target
if nums[mid] < target:
left = mid + 1
# 如果 > , 则表示[left, mid-1]中存在target
# 如果 = , 则表示[left, mid]中存在target
# 为了统一代码,将[left, mid-1]扩大至[left, mid]
else:
right = mid
# 当循环结束时,left = right,但是也有可能仍然没有找到target
if nums[left] == target:
return left
return -1
2.3.2 二分查找最后一次出现的索引
def findLastElement(nums, target):
"""target最后一次出现的位置"""
left, right = 0, len(nums) - 1
while left < right:
# left与right只相差1的时候,容易陷入死循环,因此此时mid = (left+right)//2 仍旧=left
# 如果此时有nums[mid]<=target, 那么left = mid = left, 这样一来left和right都没发生变化
# 而进行上取整后,mid=right,即使有nums[mid]<=target,left=mid=right,那么left=right也能结束循环
# 如果有nums[mid]>target,right=mid-1=left,那么仍旧结束循环。
mid = (left + right + 1) // 2
if nums[mid] <= target:
left = mid
else:
right = mid - 1
# 由于我们已经找到了第一次出现的位置,
# 所以最后一次出现的位置最不济也就是第一次出现的位置,不可能出现没找到的情况
# 因此直接返回left即可
return left
2.3.3 最终代码
def search(nums: List[int], target: int) -> int:
def findFirstElement(nums, target):
"""target第一次出现的位置"""
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) // 2
if nums[mid] < target:
left = mid + 1
else:
right = mid
# 当循环结束时,left = right,但是也有可能仍然没有找到target
if nums[left] == target:
return left
return -1
def findLastElement(nums, target):
"""target最后一次出现的位置"""
left, right = 0, len(nums) - 1
while left < right:
# left与right只相差1的时候,容易陷入死循环,因此此时mid = (left+right)//2 仍旧=left
# 如果此时有nums[mid]<=target, 那么left = mid = left, 这样一来left和right都没发生变化
# 而进行上取整后,mid=right,即使有nums[mid]<=target,left=mid=right,那么left=right也能结束循环
# 如果有nums[mid]>target,right=mid-1=left,那么仍旧结束循环。
mid = (left + right + 1) // 2
if nums[mid] <= target:
left = mid
else:
right = mid - 1
# 由于我们已经找到了第一次出现的位置,
# 所以最后一次出现的位置最不济也就是第一次出现的位置,不可能出现没找到的情况
# 因此直接返回left即可
return left
if len(nums) == 0:
return 0
left = findFirstElement(nums, target)
if left == -1:
return 0
right = findLastElement(nums, target)
return right - left + 1
时间复杂度为O ( l o g ( n ) ) O(log(n))O(log(n)),空间复杂度为O ( 1 ) O(1)O(1)
版权声明:本文为weixin_43490422原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。