【问题描述】
随机输入一个1–100以内的数x,让你设计一个程序来找这个x
【思路】
直接暴力时间复杂度就是O(n)了,即一个一个顺序的找。
今天我们用时间复杂度仅为O(lgn)的二分法来找。
说起二分,其实我很少用这个东西,因为每次都可以直接顺序搜,谁又愿意去多写个算法二分搜呢?说白了就是懒。。。但现在我发现,这个东西在很多算法题中都有涉及,关键时刻如果不加上,很容易超时。而且,二分作为一种典型的分治思想,在很多题中也有应用!
其实二分就是一个分治思路,把区间分成左右两个子区间,子问题和原问题是一样的,可以用递归写,当然一般都是用循环。二分法一般可以结合一些查找的题目,对于一个排好序的数组,能达到很快的查找速度。当然,前提是排好顺序!
参考模板:
#include<iostream>
using namespace std;
int main()
{
/*
传统暴力
for(int i = 1;i <= 100;i++)
{
if(i == x)
break;
}
*/
int x;
cin >> x; //待查找的数
int i = 100; //区间上界
int j = 1; //区间下界
int n = 0; //记录中间的元素
while(i >= j)
{
n = (i + j) / 2; //找到中间的元素,取平均值
if(n == x) {break;}
else if(x > n) j = n + 1;
else if(x < n) i = n - 1;
}
return 0;
}
核心部分实际上就是:(几行搞定)
while(i >= j)
{
n = (i + j) / 2; //找到中间的元素,取平均值,它的大小是折中的
if(n == x) break;
else if(x > n) j = n + 1;
else if(x < n) i = n - 1;
}
很多问题不会直接考你二分算法,一般都是嵌在一些难题里面考,不用的话就会超时。
递归版本:
#include<iostream>
using namespace std;
int f(int i, int j, int val)
{
int n = (i + j) / 2; //取中间值
if(n == val)
return n;
else if(val > n)
return f(n + 1, j, val);
else // val < n
return f(i, n - 1, val);
}
int main()
{
int x;
cin >> x;
cout << f(1, 100, x);
return 0;
}