二分查找,查指定值、小于k的最大值,大于k的最大值

我们经常会用到二分查找
二分查找应该很多人都会写了,今天要写一个用二分查找找到小于k的最大值的时候看了很久不懂他设计的思路,后来想通了,记录一下。
所以这篇主要是讲 用二分查找找到小于k的最大值大于k的最大值

二分查找查找指定值

这个挺简单的,直接上代码吧

 //获取值是k的位置,找不到则返回-1
    public static int getK(int[] a, int k){
        if(a.length == 0){
            return -1;
        }
        int l = 0;
        int r = a.length - 1;
        //注意这里的判断条件,是必须允许 l = r 的情况存在的
        //因为可能会出现刚好到最后左边指针到右边指针只有1个元素,而且这个元素恰恰就是我们想找的k
        while (l <= r){
            int mid = (l + r) / 2;
            //如果mid元素已经是k了,那么直接返回
            if (a[mid] == k){
                return mid;
            //查找左边的
            }else if(a[mid] > k) {
                r = mid - 1;
            //查找右边的
            }else {
                l = mid + 1;
            }
        }
        //如果没有找到指定的值,那么直接返回-1
        return -1;
    }

用二分查找找到小于或者等于k的最大值

思路:如果mid元素是小于或等于k,往右找,如果大于k,往左边找,直到找到一个值,最接近与k的。
看代码中标注了 处地方,下面解释为什么如此设计

    //获取值<=k的最大值
    public static int uperK(int[] a, int k){
        int l = 0;
        int r = a.length - 1;
        //标注1: 这里是l<r,
        while(l < r){
            //标注2: 这样的操作是为了取高位
            int mid = (l + r + 1) / 2;
            if(a[mid] <= k) { //因为a[mid]<=k,所以a[mid]可能=k,所以mid坐标也满足条件,l = mid而不是mid+1;
                l = mid;
            }else{
                r= mid - 1; //这是a[mid] > k的时候。
            }
        }
        //因为此时求得到的是最接近于目标值k的数,
        // 1. 如果最小值都大于k的话,那么就没有办法得到了,所以就进行一个判断
        if(a[l] > k) return -1;
        return a[l];
    }
  • 标注1解释:
    因为我们的目的是“通过缩小范围,得到当l = r的时候,l 标记的值”的情况,所以直到 l< r条件被打破的时候的l就是我们要求的值。这跟上一道问题“查找指定值”是不一样的
  • 标注2解释:
    标注2: 这样的操作是为了让 mid 标志 取高位, 才能让循环顺序跳出来,举个死循环的例子
    注意这个例子采取的是mid = (l + r) / 2 取低位的情况,为了展示死循环的形成过程,我们原题的做法是取高位的

    数据: int[] num = {1,2,3,4,5,6,7,8,9}, 查找小于或者等于8的最小值。


如上图,此时左坐标是0, 右是8, 那么
mid = (0 + 8) / 2 = 4,num[mid] = num[4] <= k, ,向右找结果,所以有 l = mid,开始下一个循环。


此时的mid = 6, num[6] = 7;
num[mid] <= k, 向右找 l = 6
下一步:

可以得到 l = 6, r = 8, mid = (6+8) / 2 = 7,a[7] = 8 <= k,那么有l = mid = 7, r = 8,
推到得到mid = 7, 问题来了上一步的时候mid已经是7了,结果会使得mid一直是7,一直循环下去。
所以如果我们求的是二分法求小于或者等于k的最大值的话,我们mid 必须取得中值的上界,

原文地址:https://www.cnblogs.com/disandafeier/p/11020559.html

时间: 2024-10-08 21:04:14

二分查找,查指定值、小于k的最大值,大于k的最大值的相关文章

二分查找(等于x,小于x,小于等于x,大于x,大于等于x )

//等于x//小于x//小于等于x//大于x//大于等于x 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <set> 7 #include <map> 8 #include <list> 9 #include <stack>

【经典算法——查找】二分查找

二分查找又称为折半查找,仅适用于事先已经排好序的顺序表.其查找的基本思路:首先将给定值K,与表中中间位置元素的关键字比较,若相等,返回该元素的存储位置:若不等,这所需查找的元素只能在中间数据以外的前半部分或后半部分中.然后在缩小的范围中继续进行同样的查找.如此反复直到找到为止.算法如下: 1 template<typename T> 2 int BinarySearch(vector<T> &data, T key) { 3 int low = 0, high = data

二分查找算法的 JavaScript 实现

二分查找在查找[指定值]在[有序]数据中的[位置]时是一种高效的算法. 以下仅提供 ES5 版本. var arr = [0, 2, 4, 27, 28, 54, 67, 74, 75, 79, 86, 97, 289, 290, 678] function binarySearch(arr, val) { var start = 0, end = arr.length - 1; while (start <= end) { var mid = Math.floor((start + end)

二叉查找树(4) - 中序查找一个给定值的前驱以及后继

假设树的节点定义如下,查找一个指定值的前驱以及后继节点.如果树中没有找到指定值,则返回它所在区间的边界值. struct Node {    int key;    Node *left,*right ; }; 下面是实现此操作的算法,采用递归: 输入: 根节点, 键值 输出: 前驱节点,后继节点 1. If root is NULL then return 2. if key is found then a. If its left subtree is not null Then prede

【模板】二分查找

二分查找就是指对于一个有序数列,取其中间值,与要查找的值比较,若大于,则舍弃右半部分序列,若小于则舍弃左半部分序列,其复杂度是O(logn)的.二分查找看似简单,但到处都说要想不出错很难. inline int search(int *arr,int size,int key) { //内联查找函数,参数为序列数组,数组大小及查找的值     int left=0,right=size; //定义整型变量left置为0,right置为size     int mid; //定义整型变量mid  

算法图解(二分查找)

前言: 今天是第一篇 以后尽量每天写 看具体时间安排吧 目前一边学Python.Java.Go还有算法 所以写的比较少 主要是Python一天差不多16小时吧 Java.go看时间安排 这次算法全是用Python演示的 不懂Python的也没关系 或者可以看一下我前面的帖子 算法是什么: 算法是一只组完成任务的指令  要么速度快.要么能解决问题 应该说是为实现某些目的的逻辑 以及 思想 的代码 二分查找 假设你要查找电话本里k开头的人 里可能会直接滑动到中间 因为你知道k在中间位置 因为电话本是

【剑指offer】二分查找二维数组

转载请注明出处:http://blog.csdn.net/ns_code/article/details/24977113 剑指offer上的第三道题目.在九度OJ上測试通过 题目描写叙述: 在一个二维数组中,每一行都依照从左到右递增的顺序排序.每一列都依照从上到下递增的顺序排序.请完毕一个函数,输入这种一个二维数组和一个整数,推断数组中是否含有该整数. 输入: 输入可能包括多个測试例子,对于每一个測试案例, 输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和

【BZOJ2594】水管局长加强版,LCT+并查集+二分查找位置

Time:2016.05.10 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: LCT维护路径最小值 倒叙处理询问,就相当于往图里面加边. 实时维护最小值,即最小生成树,可以参照魔法森林. 最初的最小生成树操作用kruskal 最蛋疼的是处理询问时你不知道要删除哪条边,这给kruskal带来很大麻烦,所以我们对原来的每一条边使其编号小的端点在前,大的在后,然后以左端点为第一关键字,右端点为第二关键字排序,记录下每个左端点的所在区间,然后就可以通过二分查找的方式来确定是哪条边了

hiho week 37 P1 : 二分&#183;二分查找之k小数

P1 : 二分·二分查找之k小数 Time Limit:10000ms Case Time Limit:1000ms Memory Limit:256MB 描述 在上一回里我们知道Nettle在玩<艦これ>,Nettle的镇守府有很多船位,但船位再多也是有限的.Nettle通过捞船又出了一艘稀有的 船,但是已有的N(1≤N≤1,000,000)个船位都已经有船了.所以Nettle不得不把其中一艘船拆掉来让位给新的船.Nettle思考了很久, 决定随机选择一个k,然后拆掉稀有度第k小的船. 已知