给定一个已排序的数组和一个目标值,如何快速统计该目标值在数组中出现的次数?这是面试中非常经典的一道题,今天就来聊聊两种解法:线性搜索和二分搜索。
问题描述
假设有一个已排序的数组 arr[] 和一个整数 target,需要找出 target 在数组中出现的次数。
示例:
-
输入:
arr[] = [1, 1, 2, 2, 2, 2, 3],target = 2 -
输出:
4(2 出现了 4 次) -
输入:
arr[] = [1, 1, 2, 2, 2, 2, 3],target = 4 -
输出:
0(4 不在数组中)
方法一:线性搜索(暴力法)
思路: 遍历整个数组,遇到与目标值相等的元素就计数加 1。
代码实现(Python):
python
def countFreq(arr, target):
res = 0
for i in range(len(arr)):
if arr[i] == target:
res += 1
return res
arr = [1, 1, 2, 2, 2, 2, 3]
target = 2
print(countFreq(arr, target)) # 输出 4
复杂度分析:
- 时间复杂度:O(n),因为需要遍历整个数组。
- 空间复杂度:O(1),只用了常数空间。
这种方法简单直观,但当数组很大时效率较低。
刷算法题时,遇到"排序数组中查找目标元素出现次数"这类问题,你是不是也卡在边界条件和二分查找的细节上?其实,理解这类问题的核心,关键在于把抽象的逻辑"看"清楚。强烈安利一个神器------图码,它提供60多种数据结构和算法的交互式动画可视化,能帮你把二分查找的每一步都"动"起来。更绝的是,你可以直接上传自己的C/C++/Java/Python代码,或者输入自定义数据,让网站自动生成动画,直观看到代码执行过程。无论你是备战408考研,还是准备数据结构期末考试,它都能把晦涩的算法拆解得明明白白。现在就去看看吧,说不定能让你少走很多弯路!
图码-数据结构与算法交互式可视化平台
访问网站:https://totuma.cn
方法二:二分搜索(最优解)
既然数组是已排序的,我们可以利用二分搜索来加速。核心思想是:
- 找到目标值的 第一次出现位置(下界)
- 找到 第一个大于目标值的位置(上界)
- 两者之差就是目标值的出现次数
代码实现(Python,使用内置函数):
python
from bisect import bisect_left, bisect_right
def countFreq(arr, target):
l = bisect_left(arr, target)
r = bisect_right(arr, target)
return r - l
arr = [1, 2, 2, 2, 2, 3, 4, 7, 8, 8]
target = 2
print(countFreq(arr, target)) # 输出 4
手动实现二分搜索(C++ 风格):
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int countFreq(vector<int> &arr, int target) {
int l = lower_bound(arr.begin(), arr.end(), target) - arr.begin();
int r = upper_bound(arr.begin(), arr.end(), target) - arr.begin();
return r - l;
}
int main() {
vector<int> arr = {1, 2, 2, 2, 2, 3, 4, 7, 8, 8};
int target = 2;
cout << countFreq(arr, target); // 输出 4
return 0;
}
复杂度分析:
- 时间复杂度:O(log n),两次二分搜索,每次 O(log n)。
- 空间复杂度:O(1)。
为什么二分搜索更快?
线性搜索需要遍历整个数组,当数组有 10 万个元素时,最坏情况要比较 10 万次。而二分搜索每次将搜索范围减半,只需比较约 log₂(100000) ≈ 17 次。
总结
| 方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 线性搜索 | O(n) | O(1) | 小数组或未排序数组 |
| 二分搜索 | O(log n) | O(1) | 已排序的大数组 |
如果数组是已排序的,强烈推荐使用二分搜索,效率高且实现简单。如果数组未排序,可以先排序再二分,但排序本身需要 O(n log n) 时间,此时线性搜索可能更合适。
希望这篇文章对你有帮助!如果你有其他解法或问题,欢迎在评论区讨论~