二分思想

#include<cstdio>
using namespace std;
//二分查找
int bsrch(int l,int r,int k,int a[])
{
    int mid;
    while(l<=r){
        mid=(l+r)/2;
        if(a[mid]>k)r=mid-1;
        else if(a[mid]==k)return mid;
        else l=mid+1;
    }
    return -1;
}
//有序区间下界//第一个大于等于k的元素的位置
int lowerBound(int l,int r,int k,int a[])
{
    while(l<r){
        int mid=(l+r)/2;
        if(a[mid]>=k)r=mid;//进入左子区间[l,mid]
        else l=mid+1;//进入右子区间[mid+1,r]
    }
    return l;
}
//有序区间上界//第一个大于k的元素位置
int upperBound(int l,int r,int k,int a[])
{
    while(l<r){
        int mid=(l+r)/2;
        if(a[mid]>k)r=mid;
        else l=mid+1;
    }
    return l;
}
int main()
{
    int a[]={1,2,3,3,3,3,3,4,5,6,7};
    int l=0,r=10;
    int k=3;
    printf("%d\n",bsrch(0,10,k,a));
    printf("%d\n",lowerBound(0,10,k,a));
    printf("%d\n",upperBound(0,10,k,a));
    while(1);
}

这是三段非常相似的代码。二分查找比较明确,难懂的是下面的两段代码。大体的思路沿袭二分的想法,区别就在于搜索左右子区间的条件不同。

可以注意到一个特点,lowerBound返回的下标对应的值一定大于等于k,循环结束的条件是l==r,所以满足条件,upperBound类似。

写成递归形式可能更容易理解,下面就是lowerBound的递归形式

int lowerBound_r(int l,int r,int k,int a[])
{
    if(l==r)return l;
    int mid=(l+r)/2;
    if(a[mid]>=k)return lowerBound_r(l,mid,k,a);
    else return lowerBound_r(mid+1,r,k,a);
}

从递归看返回的就是最左边的大于等于k的值

类似得出upperBound的递归形式

int upperBound_r(int l,int r,int k,int a[])
{
    if(l==r)return l;
    int mid=(l+r)/2;
    if(a[mid]>k)return upperBound_r(l,mid,k,a);
    else return upperBound_r(mid+1,r,k,a);
}

返回最左边的大于k的位置

原文地址:https://www.cnblogs.com/MalcolmMeng/p/8452038.html

时间: 2024-10-28 05:04:09

二分思想的相关文章

数据结构与算法学习之路:LIS——最长递增序列的动态规划算法和二分思想算法

一.最长递增序列的问题描述: 求一个整数序列的最长递增子序列,子序列不要求是连续的.例如: Input:4,6,9,6,7,6,3,8,10:Output:5 二.解决方法: 1.用动态规划的方法解决.从问题我们可以知道,我们最终得到的最长递增子序列,其任意一段子序列也是对应序列中的最长子序列.这样说可能不好理解,就以上面的例子来说: 最长子序列为:4,6, 7, 8, 10.在这段子序列的子序列里选一个,例如:4,6,7.则4,6,7也是4,6,9,6,7,6,3这段序列的最长子序列. 对于动

poj 3111 K Best 最大化平均值 二分思想

poj 3111 K Best 最大化平均值 二分思想 题目链接: http://poj.org/problem?id=3111 思路: 挑战程序竞赛书上讲的很好,下面的解释也基本来源于此书 设定条件C(x):=可以选择使得单位重量的价值不小于x 如何判定C(x)是否可行 假设选了某个物品的集合是S,那么单位重量的价值是:\[ \sum\limits_{i \in S} {v_i } /\sum\limits_{i \in S} {w_i } \] 因此就变成了判断是否存在S满足下面的条件:\[

poj2299 二分思想

poj2299   http://poj.org/problem?id=2299题意: 一个含有n个数的数组, 每次只能交换相邻的两个数, 求最少操作多少次可以使该数组变成一个有序数组(从小到大). 分析: 先说一下归并排序吧. 二分的思想, 就是将一元素集合分割成两个或更多个子集合,对每一个子集合分别排序,然后将排好序的子集合归并为一个集合.看图理解会好一点!  归并排序核心操作:将一维数组中前后相邻的两个有序序列归并为一个有序序列. 那看一下我们这题, 其实就是在归并排序的过程中顺便计算一下

对二分思想的理解及结对编程

一.对二分法思想的体会 1.二分法是运用分治策略的典型例子,也称折半查找,充分利用了元素间的次序关系,是一种效率较高的查找方法.实现二分算法有递归和非递归两种方式. 2.基本思想:将n个元素分成大致相同的两半,取a[n/2]与x作比较.如果x=a[n/2],则找到x,算法终止:如果a<[n/2],则只在数组a的左半部分继续搜索x:如果x>a[n/2],则只在数组的右半部分继续搜索x. 3.代码实现: int BinarySearch(Type a[],const Type&x,int

背包/母函数?/二分思想?

1033: 空运物资 时间限制: 1 Sec  内存限制: 128 MB提交: 8  解决: 4[提交][状态][讨论版][Edit] [TestData] 题目描述 在灾区,多数人已经受伤,缺水,少食物,精神处在崩溃的边缘.很多人的生存条件仅能维持几天.灾民需要帐篷.衣物.食品和医疗器材.药品等物资.14日上午,中央军委委员.空军司令员许其亮组织召开空军首长办公会,将空军下一步救灾重点确定为抢救伤员.空投.空运.空军各部队都派出多架运输机,准备向灾区空运急需物品.现在已知四种打包过的急需物品重

The Sum of 0 for four numbers(拆解加二分思想)

个人心得:单纯用二分法一直超时,后面发现我的那种方法并没有节省多少时间,后面看了大神的代码,真的是巧妙, 俩个数组分别装a+b,c+d.双指针一个指向最后,从第一个开始想加,加到刚好大于0停止,再看是否存在和为0的情况. 很巧妙,因为此时i,j所指想加刚好大于0,因为是排完序的,所以i往后面走的时候,大于j的数相加一定大于0,所以卡的非常好: 就没有再指针跳转回去了,佩服! The SUM problem can be formulated as follows: given four list

算法与数据结构总结1 二分查找与旋转排序数组

一. 二分搜索(Binary Search)模板及其理解 1.通用模板,解决start, end, mid, <(<=), >(>=)等问题 http://www.lintcode.com/en/problem/binary-search/ class Solution { public: /** * @param nums: The integer array. * @param target: Target number to find. * @return: The firs

二分查找如何“花式”卖萌

二分查找,敢说这货埋在土里化到灰里应该都是认得的.其原理思想也是如此的简单明了,敲代码时都懒得经过反射弧.但事实上,据Knuth神犇描述,第一个木有bug的二分查找是这个算法发表之后12年在出现,但后来发现还是存在一些数组越界的小问题.而如今,我们大都是开门见山的学习被前辈们优化证明的算法,这也是“牛逼顿”所谓的站在巨人的肩膀上,却也如此. 回头来看二分查找如何“花式”卖萌. Problem:给定一个有序数组A,且数组中的元素存在重复,各大一个目标值target,求目标值在数组的的下标的区间(即

POJ2109 高精度(含大数开方)+二分

1 高精度(含大数开方)+二分 一个技巧和三点注意: 技巧:假设k^n=p;(k的n次方),那么p的位数/n得到的是k的位数!例如:n=7,p=4357186184021382204544,p的位数为22,用22/7的结果向上取整,得到4,即为k的位数,也就是说k的取值范围是1000~9999.(引自code_pang)不利用这一点,高精度+直接二分,也会超时.用这一个技巧合理缩小二分的范围. 注意:看code的main中的注释. (二分思想不熟练,因为二分算法很高效,所以一定要暴力点直接确定l