D2.二分

二分的本质不是单调性。具有单调性一定可以二分,不具有单调性或许能够二分;
二分的本质类似“边界”:如果根据某个性质,把整个区间一分为二,一部分满足这个性质,另一部分不满足这个性质 ,二分就可以寻找两部分的边界

1.整数二分

存在边界问题。

  1. 使用循环来查找边界(目标)所在的下标。check(mid)表达式用来检查mid是否满足某种性质,根据结果是true还是false来分析区间的更新方式:1) true:l = mid; false: r = mid-1;2) true: r = mid; false: l = mid+1;因为是整数二分,两个区间之间没有交点,两个模板分别是求两个边界的下标。显然两个边界点一定是紧挨着的。

  2. 这两种方式各自的true和false是一一对应的!注意如果是第一种情况改mid = (l+r+1) / 2;

  3. 整体思路就是,首先打模板,然后画图分析出查询值x的满足性质以及划分区间,进一步写出true和false、修改mid。
    注意while循环结束之后,l == r ,退出循环。
    注意三个式子的对应关系:
    mid = (l+r+1) / 2 <-- l = mid --> r = mid - 1
    mid = (l+r) / 2 <-- r = mid --> l = mid + 1 .

  4. 主要是看一下x到底是哪个边界,满足什么性质?
    要么l = mid,要么r = mid.

#include<iostream>
using namespace std;

bool check(int x){/* 检查函数,或者是简单的表达式比较*/}

// 1)区间划分成[l,mid-1][mid,r]
int bsearch_1(int l,int r)
{
	while(l < r)
	{
		int mid = (l+r+1) / 2 ;
		if(check(mid))  l = mid;
		else r = mid - 1;
	}
	return l;
}

// 2)区间划分成[l,mid][mid+1,r]
int bsearch_2(int l, int r)
{
	while(l < r)
	{
		int mid = (l+r) / 2;
		if(check(mid)) r = mid;
		else l = mid + 1; 
	}
	return l;
}

在这里插入图片描述

  1. 二分循环,缩小后的区间都是目标x所在的区间,当区间长度是1的时候,那么这就是答案。二分一定是有解的,不同的题目可能会无解。也就是无解的时候不会找到满足等号的条件,二分找出来的就可能是单纯<或者>,而不带等号。

2.浮点数二分

浮点数二分不需要处理边界问题,当区间更新到只有很小的区间的时候,可以认为找到了答案。
想法是挺重要的,把一个问题转化为二分的问题…例如下面是使用浮点数二分求出输入值x的开方:

#include<iostream>
using namespace std;

int main()
{
	double x;
	cin >> x;
	
	double l = 0, r = x;
	for (int i = 0; i < 100; i++)
	{
		double mid = (l + r) / 2;
		if (mid*mid > x) { r = mid; }
		else l = mid;
	}
	cout << l << endl;
	return 0;
}

注意浮点数二分都是l = mid 或者 r = mid !

key:
在这里插入图片描述

刷题反思

1. 0到n-1中缺失的数字

数组方面要考虑下标和值的关系。
在这里插入图片描述

在这里插入图片描述

2.

在这里插入图片描述

注意充分利用条件!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值