算法基础——二分

算法基础(二分)

二分的性质

若一组数有单调性则一定可以二分,但可以二分的题目不一定有单调性(有单调性则一定可以二分,没有单调性也有可能可以二分)

二分的本质(边界): 若给定一组数据在这组数据上定义了某种性质,使得这个性质若在右半边满足则左半边一定不满足则可以使用二分

整数二分

代码模板

//区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用 模板1
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = (l + r) / 2;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
-----------------------------------------------------------------------------------------
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用 模板2
int bsearch_2(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 = r-1时及lr只差一的时候若mid = (l + r) / 2代入特殊值l = 1,r = 2mid = (1+2)/2 = 1mid = l区间没变进入死循环

例题: 0到n-1中缺失的数字

题目描述

一个长度为 n−1n−1 的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围 00 到 n−1n−1 之内。在范围 00 到 n−1n−1 的 nn 个数字中有且只有一个数字不在该数组中,请找出这个数字。

数据范围: 1≤ n ≤1000

样例
输入:[0,1,2,4]

输出:3
算法分析

通过上述样例可以看出缺失数字左面的数字和下标相同,而缺失数字右面的数字和小标不同,而且区间[l, r]可以通过是否下标等于对应数字被划分成[l, mid]和[mid + 1, r],所有使用模板1。另外要注意特殊情况:当所有数都满足nums[i] == i时,表示缺失的是 n。

C代码
int getMissingNumber(int* nums, int numsSize) {
    int l = 0, r = numsSize - 1, mid ;
    if(numsSize == 0) return 0;
    while( l < r)
    {
        mid = l + r >> 1;
        if(mid == nums[mid])
            l = mid + 1;
        else
            r = mid;
    }
    if(nums[r]== r) r++;
    return r;
}

浮点数二分

代码模板

double bsearch_3(double l, double r)
{
    while (r - l > 1e-6)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

注:1e-6表示计算精度,一般题目若要求精确至小数点后4位用1e-6,及精确至小数点后n位用1e-(n+2)

例题: 剪绳子

题目描述

有 N 根绳子,第 3 根绳子长度为 L₃,现在需要 M 根等长的绳子,你可以对 N 根绳子进行任意裁剪(不能拼接),请你帮忙计算出这 M 根绳子最长的长度是多少。

数据范围

1≤N,M≤100000

0<Li<10^9

输入格式

第一行包含 2 个正整数 N、M,表示原始绳子的数量和需求绳子的数量。

第二行包含 N 个整数,其中第 i 个整数 Li 表示第 i 根绳子的长度。

样例

3 4
3 5 4
输出格式

输出一个数字,表示裁剪后最长的长度,保留两位小数。

样例

2.50
样例解释

第一根和第三根分别裁剪出一根 2.50 长度的绳子,第二根剪成 2 根 2.50 长度的绳子,刚好 4 根。

算法分析

因为0<Li<10^9所有另l=0 r=1e9mid = (l + r) / 2定义一个函数判断按照长度为mid截取是否可以截取够需求的数量,若可以则证明mid左面的数均可以所以令l=mid用来判断右面的数以求出最优解;反之则证明mid右面的数均不满足,另令r=mid用来继续判断左面以找出满足的解。

C代码
#include<stdio.h>

int a[100010];
int n , m ;

int panduan(double mid)
{
    int num=0 , i;
    for(i = 0 ; i < n ; i ++)
        num += a[i] / mid;
    int t=0;
    if(num >= m) t = 1 ;
    return t;
}

main()
{
    int i;
    scanf("%d%d",&n,&m);
    for(i = 0 ; i < n ; i ++)
        scanf("%d",&a[i]);
    double l = 0 , r = 1e9 , mid ;
    while(r -l > 1e-4)
    {
        mid = (l + r) / 2 ;
        if(panduan(mid))
            l = mid;
        else
            r = mid;
    }
    printf("%.2f",l);
}

参考内容

AcWing 常用代码模板1——基础算法

AcWing 680. 剪绳子-视频讲解

AcWing 68. 0到n-1中缺失的数字 - 题解

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中的二分算法可以通过使用标准库中的`bisect_left()`函数来实现。该函数接受两个参数,一个是有序序列,另一个是目标值。它会返回目标值在序列中的插入位置,如果目标值已经存在,则返回其左侧位置。例如,如果我们有一个有序序列`a = \[1,2,2,3,5,5,5,6,7\]`,我们想要找到值为4的元素的插入位置,我们可以使用`bisect_left(a, 4)`函数来实现,它会返回2。\[2\] 另外,二分算法在解决一般最值问题时非常有用。在使用二分法解决问题时,我们需要将问题的信息建模为可以使用二分法解决的形式。通常,我们需要编写一个`check()`函数来根据题目要求进行判断。二分法本身也有一些问题,比如取整问题,但是如果使用简易的二分模板,通常不需要考虑这个问题。\[1\] 总的来说,二分法是一种高效的算法,可以在较短的时间内找到问题的解。在解决一些数量较大的问题时,二分法可以大大提高算法的效率。\[3\] #### 引用[.reference_title] - *1* *2* *3* [算法第三期——二分法(Python)](https://blog.csdn.net/m0_69478345/article/details/128442080)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值