二分【查找】

整数二分(r=mid,l=mid+1 or l=mid r=mid-1)

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)  
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;  //这里一定要+1 不然最后会停在high-low=1无线循环
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用: 
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

eg 数的范围

给定一个按照升序排列的长度为n的整数数组,以及q个查询。
对于每个查询,返回一个元素k的起始位置和终止位置(位置从О开始计数)。
如果数组中不存在该元素,则返回-1 -1。
输入格式
第一行包含整数n和q,表示数组长度和询问个数。
第二行包含n个整数(均在1~10000范围内),表示完整数组。
接下来q行,每行包含一个整数k,表示一个询问元素。
输出格式
共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回-1 -1。

在这里插入图片描述

#include<iostream>

using namespace std;

int list[100010];

int main(){
	int n,m;
	while(cin>>n>>m){
		for(int i=0;i<n;i++){
			cin>>list[i];
		}
		while(m--){
			int x;
			cin>>x;
			// 板子
			int l=0,r=n-1;
			while(l<r){
				int mid=r+l>>1;
				if(list[mid]>=x) r=mid;
				else l=mid+1;
			}
			
			if(list[l]!=x) cout<<"-1 -1"<<endl;
			else{
				cout<<l<<" ";
				//  板子
				int l=0,r=n-1;
				while(l<r){
					int mid=r+l+1>>1;
					if(list[mid]<=x) l=mid;
					else r=mid-1;
				}
				
				cout<<l<<endl;
			}
		}
	}
}

先基础一点:找递增数组中大于等于x的【最小】的元素 / 小于等于x的【最大】元素

// a[]非降
// solve函数用于返回大于等于x的最【小】元素的坐标
int solve1(int x) {
    int L = 1, R = n, ans = -1;
    while (L < R) {
        int mid = L+R>>1;
        if (a[mid] >= x) {  //选左
            R = mid ;
        }
        else L = mid + 1;
    }
    return L;
}
// solve函数用于返回小于等于x的最【大】元素的坐标
int solve1(int x) {
    int L = 1, R = n, ans = -1;
    while (L < R) {
        int mid = L+R>>1;
        if (a[mid] <= x) { //选右
        	L=mid+1;
        }
        else  R = mid ;
    }
    return L;
}

eg 疯牛

Aggressive cows
Description

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,…,xN (0 <= xi <= 1,000,000,000).

His C (2 <= C <= N) cows don’t like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

  • Line 1: Two space-separated integers: N and C

  • Lines 2…N+1: Line i+1 contains an integer stall location, xi

Output

  • Line 1: One integer: the largest minimum distance

Sample Input 1

5 3
1
2
8
4
9
Sample Output 1

3
Hint

OUTPUT DETAILS:

FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3.

题意:数轴上有固定n个点 现在要在里面选m个点,求这m个点之间的最小间隔的最大值

即max(min)

key1:二分查找【最值】 可以查出最大/最小的符合要求值(只要用ans存下就行)

key2:判断数能不能作为最小间隔 用贪心思想 逐步取点

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
const int MAX = 100010;
int a[MAX],n,m;

bool C(int d)
{
    int t = a[0],count = 1;
    for(int i = 1;i < n;i ++)
    {
        if(a[i] - t >= d)
        {
            count ++;
            t=a[i];
            if(count >= m)
                return true;
        }
    }
    return false;
}


int solve()  用二分 【查找符合条件的最大值】
{
    int x = 0,y = a[n-1] - a[0],ans=0;
    while(x < y)  板子
    {
        int mid=(x+y+1)/2;
        if(C(mid))
        {
            x=mid ;
        }
        else
            y=mid-1 ;
    }
    return x;
}


int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i = 0;i < n;i ++)
        scanf("%d",&a[i]);
        sort(a,a+n);
        printf("%d\n",solve());
    }
    return 0;
}

l=mid; r=mid; 的情况下最终停在r-l==1

求递增数组中与x最接近的数

在这里插入图片描述

二分+递归+分奇偶

编写一个int solve(int low, int high)函数求解查找假币问题。有n(3<n<1000 000 000)个硬币,下标序号为0 ~ n-1。其中恰好有一个假币,且假币较轻,采用天平称重方式找到这个假币,函数返回假币的下标序号。

系统中提供查询函数int weigh(int x, int y),你可以用硬币的下标序号来查询任意两堆硬币在天平上的状态。返回值集合为[-1,0,1],分别表示左边重、两边相等、右边重。

weigh函数提供2个重载:

// x表示下标序号为x的硬币放在天平左边,y表示下标序号为y的硬币放在天平右边。
int weigh(int x, int y);

// x1,x2表示硬币下标序号为[x1,x2]范围内的所有硬币放在天平左边,y1,y2表示硬币下标序号为[y1,y2]范围内的所有硬币放在天平右边
int weigh(int x1, int x2, int y1, int y2);
在这里插入图片描述在这里插入图片描述

浮点数二分 开根号

bool check(double x) {/* ... */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

eg: 求立方根

#include<iostream>
#include<cstdio> 
#include<iomanip>
#include<cmath>
using namespace std;

int main(){
    double a;
    cin>>a;
    //先就考虑为正数 
    int flag=1;
    if(a>=0) flag=1;
    if(a<0){
        flag=0;
        a=-a;
    } 
    double l=0,r=a+1;//范围要开大+1 因为小数根号大于自己 

    while(r-l>1e-8){
        double mid=(l+r)/2;
        if(mid*mid*mid>=a) r=mid;
        else l=mid;
    }
    if(flag)
    cout<<fixed<<setprecision(6)<<l;
    if(!flag) cout<<fixed<<setprecision(6)<<"-"<<l;
}


### 二分查找算法原理及实现代码 #### 原理 二分查找算法是一种高效的查找方法,适用于有序数组。其基本思想是通过将搜索区间不断缩小一半来查找目标元素。具体步骤如下: 1. **初始化**:设定查找的起始位置 `start` 和数组长度 `length`。 2. **计算中间位置**:通过公式 `mid = start + (length - start) // 2` 计算中间位置。 3. **比较中间元素**: - 如果中间元素等于目标值,则返回该位置。 - 如果中间元素小于目标值,则在右半部分继续查找。 - 如果中间元素大于目标值,则在左半部分继续查找。 4. **递归或迭代**:重复上述过程直到找到目标元素或者确定目标元素不存在。 #### Python 实现 以下是使用递归方式实现的二分查找算法: ```python def binSearchFunc(arr, start, length, target): if length >= 1: mid = start + (length - start) // 2 if arr[mid] == target: return mid elif arr[mid] < target: return binSearchFunc(arr, mid + 1, length - mid - 1, target) else: return binSearchFunc(arr, start, mid - 1, target) else: return -1 # 示例数组 arrays = [1, 2, 3, 5, 6, 8] # 调用二分查找函数 i = binSearchFunc(arrays, 0, len(arrays), 5) if i != -1: print(f"找到目标元素,下标为: {i}") else: print("目标元素不在数组中") ``` 输出结果为: ``` 找到目标元素,下标为: 3 ``` #### 注意事项 - 数组必须是有序的,可以是升序也可以是降序[^2]。 - 如果数组是降序排列,需要对代码进行适当修改以适应降序条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值