二分法描述
对于区间[a,b]上连续不断且f(a)·f(b)<0的函数y=f(x),通过不断地把函数f(x)的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。
示例1
寻找是否有4这个值有输出yes 否则 no
输入
5
1
2
3
4
5
输出
yes
代码
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
int n,m;
cin >> n;
int y = 4;
int a[1001];
//初始化
memset(a,0,sizeof(a));
for (int i = 0; i < n;i++)
{
cin >> m;
a[i] = m;
};
//进行排序
sort(a, a + n - 1);
int l, r, mid;//左边。右边,中间
l = 0;
r = n - 1;
int flag = 1;
while (r>=l)
{
mid = (l + r) / 2;
if (a[mid] > y) r = mid - 1;
else l = mid + 1;
if (a[mid] == y)
{
cout << "YES" << endl;
flag = 0;
break;
};
}
if (flag) cout << "NO" << endl;
};
思路
就是或者中间大小的值,如果大,则缩小区间,那值一定在左边,那另r = mid -1; 相反则 l = mid + 1; 时间复杂度为log n;
示例2
问题描述
输入n ( n≤100,000)个整数,找出其中的两个数,它们之和等于整数m(假定肯定有解)。题中所有整数都能用int 表示。下面的计算我们假色m = 10
输入
6
9
1
2
3
8
7
输出
1 9
2 8
3 7
代码
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
int n = 0;
int a[100001];
cin >> n;
int m;
int y = 10;
for (int i = 0; i < n; i++)
{
cin >> m;
a[i] = m;
}
//排序之后进行二分求解法
sort(a,a+n);
int l, r, mid;
l = 0;
r = n - 1;
for (int i = 0; i < n; i++)
{
l = i + 1;
while (r>=l)
{
mid = (r + l) / 2;
if (a[i] + a[mid] > y)
r = mid - 1;
else
l = mid + 1;
if (a[i] + a[mid] == y)
{
cout << a[i] << "\t" <<a[mid] << endl;
break;
};
}
};
}
思路
取排序后的第一个值,然后在根据2分查找法,查找剩下的值,判断是否和取的数加起来等于需要等于的数,如果有则打印,以此类推,时间复杂度为(nlogn)
总结
二分查找法适用于单调函数的查找。相比于传统的循环,效率要好很多。希望下次在遇见类似的题目时,对于基础算法的使用更加灵活,使得解题更加快速。