关于二分的一些初步探骊
以题目为例,说明的更透彻一些
输入n个整数,n < 1e5,找出其中两个数,他们之和等于整数m,保证题目有解所有整数都可以使用int表示,输出这两个整数,(中兴面试题目)
看到题目我们的第一反应:使用dfs或者是搜索进行查找,因为洛谷新手村中的这一道题 选数 P1036,但是需要注意时间,n2的复杂度再加上输入的时间会超时,洛谷中的题用搜索写的,时间复杂度太高,所以我们转而使用二分进行查找,其实是看了郭炜老师的课程才想到二分
普通二分查找思路
我们用一层循环实现查找两个数的第一个数,然后用自带函数binary_search来查找第二个数,同时我们可以可以使用不降原则来进行算法的优化,不降原则是指我们对这部分数据进行了不停的向后查找,在一定程度上可以进行优化,总的复杂度为n * log n其中log的底数为2,到10000才需要大概10几,代码如下
/* 输入n个整数,找出其中两个数,他们之和等于整数m
所有整数都可以使用int表示
输出这两个整数
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int a[N];
bool cmp(int a,int b){
return a < b;
}
int main(){
int n,m;//代表数组的长度
cin>>n>>m;
int ans1,ans2;
for(int i = 0;i < n;i++){
scanf("%d",&a[i]);
}
sort(a,a + n,cmp);
for(int i = 0;i < n;i++){
if(binary_search(a + i,a + n,m - a[i])){
//这里用到了STL中自带的二分查找,其原型是binary_search(array[],array[] + size,value)
//三个参数分别为,数组的首地址,查找的长度,查找的值
//而且一定要注意,这个函数无法返回下标,这个函数的返回值为bool类型
ans1 = a[i];
ans2 = m - a[i];
break;
}
}
cout<<ans1<<endl<<ans2<<endl;
return 0;
}
two pointers 方法,时间复杂度 n * log n
就是两个像指针一样的东西,分别指向数组的首尾,然后比较相加的和是否大于这个值,如果大于,那么尾部指针向前移动,如果小于,头部指针向后移动,最后就能找到他的值,或者是两个指针指向了同一个数,其实运用了一种贪心的思想,我永远都在找当前最利于我的情况,该方法复杂度为n,但是由于快排函数的复杂度为n * log n,总复杂度为n log n 那么下面证明其正确性
疑问在于,假如说刚好错过了怎么办,比如,只有头部指针的前一个数与尾部指针相加才正好,而此时偏大,我们只会将尾部指针继续向前移动,而不会向后移动,那么永远都找不到这个答案
但是为什么头部指针会指向正确的较小数的后一个数呢,把镜头转向移动到较小数的那一次,从那一次就会自动退出!!!
int main(){
int n,m;//代表数组的长度
cin>>n>>m;
int ans1,ans2;
for(int i = 0;i < n;i++){
scanf("%d",&a[i]);
}
sort(a,a + n,cmp);
int l = 0,r = n - 1;
while(l != r){
if(a[l] + a[r] == m){
cout<<a[l]<<endl<<a[r]<<endl;
}
if(a[l] + a[r] >m)
r--;
else if(a[l] + a[r] < m)
l++;
}
return 0;
}