传统二分
特点:
在一个有序、无重复元素的数组中找出某个关键字
二分查找步骤:
- 循环的条件是:
left <= right
1、用三个指针left
、mid
、right
分别指向数组头、中间、尾。left
与right
之间是待查找区
2、在待查找区间中,如果数组中间位置mid
指向的值等于目标值,则表示已找到目标值
3、 否则:
①. 如果数组中间位置mid
指向的值小于目标值,则更新待查找区的最左端为中间位置mid
的后一个位置:left = mid + 1
②. 如果数组中间位置mid
指向的值大于目标值,则更新待查找区的最右端为中间位置mid
的前一个位置:right = mid - 1
【注意】: 当right
和left
指向相同的值时:如果目标值等于该值,则找到,否则,表示该数组中没有目标值。
4、 反复进行,直到查找成果或范围缩小为空(left > right)即查找不成功为止
代码演示:
int binary_search(int target, int *num, int len) {
int left = 0, right = len - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (target == num[mid]) return mid;
else if (target > num[mid]) left = mid + 1;
else right = mid - 1;
}
//找不到,返回-1
return -1;
}
01问题之找出第一个1的位置
问题:
一串字符串,前部分由小写组成,后部分由大写组成,找出字符串中第一个大写字母。
思路:
将所有大写字母全用1
来表示,小写字母用0
表示
步骤:
- 循环的条件是:
left < right
-
写一个函数,用来把单个字符变为
0
或1
-
用三个指针
left
、mid
、right
分别指向数组头、中间、尾。 -
如果数组中间位置
mid
指向的字符等于1
(即该字符是大写),则让尾部right
更新到mid
所站的位置:right = mid
(因为right更新到的mid位置有可能是第一个1出现的位置)
-
否则如果数组中间位置
mid
指向的字符不是1
,让left
更新到mid
的后一个位置:left = mid + 1
(因为已经确定mid指向的是小写)
-
当
(left == right)
时,就表示找到了第一个大写字母,否则找不到第一个大写字母
代码演示:
int is_A(char str) {
if (str >= 'A' && str <= 'Z') {
return 1;
}
return 0;
}
int find_first_capital_letter(char *str, int len) {
int left = 0, right = len - 1, mid;
while (left < right) {
mid = (right + left ) / 2;
if (is_A(str[mid]) == 1) right = mid;
else left = mid + 1;
}
if (right == left) return left;
return -1;
}
01问题之找出最后一个0的位置
步骤:
- 头(left),尾(right),中间(mid)三个指针
- 如果
mid
是0
,left
调到mid
的位置:left = mid;
- 如果
mid
是1
,right
调到mid
的前一个位置:right = mid - 1;
(详细步骤参看01问题之找出第一个1的位置)
二分法进行数值运算——求解方程
题目:
给你一个方程:x^4 + 5 * x^3 + 6 * x^2 + 7 * x + 4 = y
,接受一个参数y
,求出y
值对应的、在0到100的范围内的解x
,并返回,若范围内没有,则返回-1
.
思路:
无穷趋近于一个值,我们就说这个值是他的解
【注意】 当y < 4
和y > x^4 + 5 * x^3 + 6 * x^2 + 7 * x + 4
时(即等式不成立时),直接返回-1
(无解)
步骤:
- 设三个指针分别指向头,中,尾,其中,头=区间头,尾=区间尾
- 如果等式左边结果小于等于y,则
left
更新为mid
所在的位置 - 如果等式左边结果大于y,则
right
更新为mid
所在的的位置
代码演示:
#include <math.h>
#define ESP 1e-6
double solve_equation(double y) {
if (4 > y || y > pow(100, 4) + 5 * pow(100, 3) + 6 * 100 * 100 + 7 * 100 + 4) return -1;
double left = 0, right = 100, mid;
while (right - left > ESP) {
mid = (left + right) / 2;
if (pow(mid, 4) + 5 * pow(mid, 3) + 6 * mid * mid + 7 * mid + 4 <= y) left = mid;
else right = mid;
}
return left;
}