1. 题目描述
描述:统计一个数字在排序数组中出现的次数。
比如{1,2,2,3,3,3,4,5,6},3出现了3次,2出现了2次。
2. 题目解析
2.1 考察问题
本问题考察的是二分查找的变体问题。
此问题并未指明排序是升序还是降序,默认为升序排列。
2.2 解决方法
- 一次遍历,计算次数
最简单直观的想法一定是顺序遍历,找到目标元素继续遍历进行计数,直到非该元素截止。
时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1) - 二分查找变体问题
对于一个有序数组,查找某个元素的方式必然首选二分查找,但是这里是统计出现次数。其实思路很简单,找到元素后,前后遍历统计计数即可。
时间复杂度 O ( l o g n ) O(logn) O(logn),空间复杂度 O ( 1 ) O(1) O(1)
2.3 优化分析
一次遍历搜索计数固然简单好用,但是并非本题考察的真实意图,从时间复杂度角度来看也并非最佳选择。
考虑到是已排序的数组,必然可以通过二分查找进行元素检索,统计计数是检索到的后续操作。
3. 代码实现
3.1 一次遍历,计算次数
class Solution:
def GetNumberOfK(self, data, k):
### 默认升序排列
# write code here
count = 0
for num in data:
if num == k:
count += 1
return count
3.2 二分查找
class Solution:
def GetNumberOfK(self, data, k):
### 默认升序排列
if len(data) == 0:
return 0
left = 0
right = len(data) - 1
mid = -1
while left <= right:
mid = left + (right - left) / 2
if data[mid] == k:##找到目标元素
lM = mid - 1
rM = mid + 1
count = 1
while lM >=0 and data[lM] == k:## 左右遍历计数
lM -= 1
count += 1
while rM <= len(data) - 1 and data[rM] == k:## 左右遍历计数
rM += 1
count += 1
return count
elif data[mid] < k:
left = mid + 1
else:
right = mid - 1
return 0
4. 思考
从代码实现来看,第一种方式既简单明了,实现还很简洁。那么为什么要用二分查找这个难写又难理解的程序呢?
这就是算法的本质目的,就是为了更加充分的利用计算机资源,用大脑的复杂思考换取计算机的计算速度,这和用时间换空间,用空间换时间,异曲同工。