题目
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
限制:
0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof
解法一:直接遍历计数/map计数
–执行时间:8 ms --消耗内存:4.1 MB
func search(nums []int, target int) int {
var time int
for _,v:=range nums{
if target<v{
break
}
if target==v{
time++
}
}
return time
}
解法二:二分查找左右边界
解题思路
-
while(left < right) 在退出循环的时候,一定有 left == right成立
- 因此,在循环中,不断排除不是目标元素的区间,以确定下一轮搜索的区间,进而确定边界如何设置
- 在退出循环的时候,根据情况,需要单独做一次判断
-
在循环体里,对 nums[mid] 与 target 的大小关系的判断,可以二分,也可以三分,本题采用三分去判断,只是为了演示怎么设置边界
- 先得到目标元素可能在哪个区间里,然后再设置边界,这样不容易出错
- 二分的好处是只要一边判断是正确的,另一边就是其反面,考虑的内容会少一些
-
看到边界是 left = mid 的时候,取中间数的计算表达式应该上取整,即在括号里加 1
-
编码时应该先写主干逻辑,然后分支逻辑作为私有函数。
解题思路引用自作者:liweiwei1419
代码
–执行时间:8 ms --消耗内存:4.1 MB
func search(nums []int, target int) int {
if len(nums)==0{
return 0
}
if len(nums)==1 && nums[0]!=target{
return 0
}
firstPoint:=getFirstPoint(nums,target)
if firstPoint==-1{
return 0
}
lastPoint:=getLastPoint(nums,target)
return lastPoint-firstPoint+1
}
func getLastPoint(nums []int, target int) int{
left:=0
right:=len(nums)-1
for left<right{
// 注意,以下 nums[mid] < target 以及 nums[mid] == target 的情况可以合并
// 边界是 left = mid ,取中间数的时候必须 + 1
mid:=(left+right+1)>>1
if nums[mid]<target{
// mid 以及 mid 左边都不是,下一轮搜索区间在 [mid + 1, right]
left=mid+1
}else if nums[mid]==target{
left=mid
}else{
// 此时 nums[mid] > target
// mid 以及 mid 右边都不是,下一轮搜索区间在 [left, mid - 1]
right=mid-1
}
}a
return right
}
func getFirstPoint(nums []int, target int) int{
left:=0
right:=len(nums)-1
for left<right{
mid:=(left+right)>>1
if nums[mid]<target{
// mid 以及 mid 左边都不是,下一轮搜索区间在 [mid + 1, right]
left=mid+1
}else if nums[mid]==target{
// mid 可能是,mid 右边一定不是,下一轮搜索区间在 [left, mid]
right=mid
}else{
// 此时 nums[mid] > target
// mid 以及 mid 右边都不是,下一轮搜索区间在 [left, mid - 1]
right=mid-1
}
}
if nums[left]!=target{
return -1
}
return left
}