目录
总起
二分法是一种常用的搜索算法,也被称为二分搜索或折半搜索。它的基本思想是通过将问题的搜索空间划分为两个较小的子问题,再对子问题进行递归地求解,最终找到问题的解。二分法的时间复杂度为O(log n),其中n是搜索空间的大小。
二分法的核心步骤可以概括为以下几个部分:
1. 确定搜索空间:首先需要确定问题的搜索空间,即待搜索的区间或集合。通常情况下,搜索空间是已经排序的。如果搜索空间不是有序的,需要首先对其进行排序。
2. 确定边界:根据问题的要求,确定搜索空间的边界。边界包括左边界和右边界。左边界一般情况下是搜索空间的起始位置,右边界一般情况下是搜索空间的结束位置。
3. 开始二分搜索:根据边界确定的搜索空间,计算中间位置的索引。如果中间位置的元素等于目标值,则返回该位置;如果中间位置的元素大于目标值,则在左半部分继续进行二分搜索;如果中间位置的元素小于目标值,则在右半部分继续进行二分搜索。重复以上步骤直到找到目标值或者搜索空间为空。
4. 返回结果:如果找到目标值,则返回目标值的位置;如果搜索空间为空,则表示目标值不存在,返回相应的标识。
二分法的优点有以下几个方面:
1. 时间复杂度低:二分法的时间复杂度为O(log n),其中n是搜索空间的大小。相比线性搜索的时间复杂度O(n),二分法的时间复杂度更低,尤其在处理大规模数据时表现出色。
2. 适用广泛:二分法适用于各种问题的解决,包括但不限于在有序数组中查找某个元素的位置、在有序矩阵中查找某个元素的位置、寻找函数的根等。无论是在算法竞赛、软件开发还是科学研究中,二分法都经常被使用。
3. 可扩展性强:二分法的思想可以扩展到更复杂的问题中。例如,在有序数组中查找某个元素的位置可以扩展到查找第一个大于目标值的元素、查找最后一个小于目标值的元素等。
时间复杂度
二分时间复杂度为O(logn),其中n为数组或列表的大小。下面是二分法的时间复杂度优点的介绍:
-
快速:二分法的时间复杂度为O(logn),相比线性搜索的时间复杂度O(n),可以大大减少搜索的时间。尤其是在大型数组或列表中查找目标元素时,二分法可以比线性搜索快很多倍;
-
高效:由于二分法是通过对数组或列表进行二分切割来逐步缩小搜索范围的,所以它对于大型数据集也非常高效。即使数据集非常庞大,二分法也可以快速找到目标元素所在的位置;
-
稳定:由于二分法是在有序数组或有序列表上进行搜索,所以只要数据集是有序的,二分法就能稳定地找到目标元素的位置。这使得它非常适合在静态数据集上进行搜索;
-
适用范围广:二分法不仅适用于数组和列表,还可以应用于其他有序数据结构,如二叉搜索树等。只要数据结构满足有序性的要求,就可以使用二分法进行快速搜索。
空间复杂度
二分法的空间复杂度有以下几个优点:
-
空间复杂度低:二分法的空间复杂度通常较低。在进行二分搜索时,只需要额外的常数级别的空间来存储一些辅助变量,如指针、临时变量等。相比其他搜索算法,如广度优先搜索或深度优先搜索,二分法不需要额外的数据结构来存储搜索过程中的状态信息,因此空间开销较小。
-
搜索空间被有效地缩小:二分法通过将搜索空间划分为两个较小的子问题来进行搜索。每一次二分操作都将搜索空间的大小减半,因此在一次二分操作后,搜索空间的大小就会减少一半。通过不断地进行二分操作,搜索空间会被迅速缩小,最终找到问题的解。这种有效地缩小搜索空间的特性使得二分法在解决大规模问题时表现出色。
-
可以处理大规模数据:由于二分法的搜索空间被有效地缩小,它可以有效地处理大规模的数据。即使在数据量非常大的情况下,二分法也能够在较短的时间内找到问题的解。这是因为二分法的时间复杂度为O(log n),其中n是搜索空间的大小。相比其他搜索算法,例如线性搜索的时间复杂度为O(n),二分法的时间复杂度更低,因此更适用于处理大规模数据。
例题(洛谷P1571 眼红的Medusa)
题目描述
虽然 Miss Medusa 到了北京,领了科技创新奖,但是她还是觉得不满意。原因是:他发现很多人都和她一样获了科技创新奖,特别是其中的某些人,还获得了另一个奖项——特殊贡献奖。而越多的人获得了两个奖项,Miss Medusa就会越眼红。于是她决定统计有哪些人获得了两个奖项,来知道自己有多眼红。
输入格式
第一行两个整数 n,m,表示有 n 个人获得科技创新奖,m 个人获得特殊贡献奖。
第二行 n 个正整数,表示获得科技创新奖的人的编号。
第三行 m 个正整数,表示获得特殊贡献奖的人的编号。
输出格式
输出一行,为获得两个奖项的人的编号,按在科技创新奖获奖名单中的先后次序输出。
输入输出样例
4 3
2 15 6 8
8 9 2
2 8
思路
此时,我们可以不用二分。
在STL中,有一个事先为我们准备好的函数——binary_search,它会二分查找一个数组中是否有一个数。
核心代码
于是,我们写出了以下代码:
for(long long i=1;i<=n;i++){
if(binary_search(b+1,b+1+m,a[i])){//二分查找函数
vec.push_back(a[i]);
}
}
这就是我们的核心代码。
小贴士
别忘了用sort给b数组排序!!
但别给a排序!!
AC代码
#include<bits/stdc++.h>
using namespace std;
long long a[100005];
long long b[100005];
struct node{
};
vector<long long>vec;
int main(){
long long n,m;
cin>>n>>m;
for(long long i=1;i<=n;i++){
cin>>a[i];
}
for(long long i=1;i<=m;i++){
cin>>b[i];
}
sort(b+1,b+1+m);
for(long long i=1;i<=n;i++){
if(binary_search(b+1,b+1+m,a[i])){
vec.push_back(a[i]);
}
}
for(int i=0;i<vec.size();i++){
cout<<vec[i]<<" ";
}
}
总结
总的来说,二分法是一种高效、广泛应用的搜索算法,它通过将问题的搜索空间划分为两个较小的子问题来快速定位目标值。它的时间复杂度低,适用性广泛,可扩展性强,是解决各种问题的强大工具。