算法-05-二分查找

news2024/11/15 10:47:53

二分查找(Binary Search)算法,也叫折半查找算法,是一种针对有序数据集合的查找算法。

1-二分查找的思想

        我们生活中猜数字的游戏,告诉你一个数据范围,比如0-100,然后你说出一个数字,我告诉你的目标数字比你的大还是小,你继续猜,根据二分查找的思想,你只要几次就可以猜中。比如目标值68。

每次猜一个数字,通过告知结果后,排除掉一半的数字,这种思想就是二分查找。

      二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0

      折半的思想从而使得二分查找的时间复杂度是O(logn)。这是一种极其高效的时间复杂度;因为logn是一个非常“恐怖”的数量级,即便n非常非常大,对应的logn也很小。比如n等于2的32次方,大约是42亿。也就是说,如果我们在42亿个数据中用二分查找一个数据,最多需要比较32次。

2-二分查找实现

       假设数组中不存在重复的元素(数组中的元素有序,并且从小到大排序好),查找数组中是否存在某个元素,存在就返回元素在数组中的下标;不存在就返回-1。

   /**
     * 查询数组中等于 target 的 索引
     * 数组中没有重复的元素
     *
     * @param array  待查找的数组
     * @param target 目标值
     * @return 数组下标索引,没有查询到返回-1
     */
private static int binarySearch01(int[] array, int target) {
        int low = 0;
        int high = array.length - 1;
        while (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (array[mid] == target) {
                return mid;
            }
            if (array[mid] > target) {
                high = mid - 1;
            }
            if (array[mid] < target) {
                low = mid + 1;
            }
        }
        return -1;

}

3-二分查找的特点

(1)二分查找依赖的是顺序表结构,简单点说就是数组。
(2)二分查找针对的是有序数据。
(3)数据量太小不适合二分查找。但是如果数据之间的比较操作非常耗时,不管数据量大小,我都推荐使用二分查找。比如,数组中存储的都是长度超过300的字符串,如此长的两个字符串之间比对大小,就会非常耗时。我们需要尽可能地减少比较次数,而比较次数的减少会大大提高性能,这个时候二分查找就比顺序遍历更有优势。
(4)数据量太大也不适合二分查找。二分查找的底层需要依赖数组这种数据结构,而数组为了支持随机访问的特性,要求内存空间连续,对内存的要求比较苛刻。

4-二分查找的变形问题

4.1-查找第一个值等于给定值的元素

      上面的二分查找算法中,要求数组中存在不重复的数字,现在我们取消这个限制,查找数组中第一个值等于给定值的元素。

    /**
     * 查询数组中第一个等于target的数字,返回数组的索引
     *
     * @param array  目前数组
     * @param target 目标值
     * @return 数组下标索引,没有查询到返回-1
     */
    private static int binarySearch02(int[] array, int target) {
        int low = 0;
        int high = array.length - 1;
        while (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (array[mid] == target) {
                if ((mid == 0) || array[mid - 1] != target) {
                    return mid;
                } else {
                    high = mid - 1;
                }
            }
            if (array[mid] > target) {
                high = mid - 1;
            }
            if (array[mid] < target) {
                low = mid + 1;
            }
        }
        return -1;
    }

      如果mid等于0,那这个元素已经是数组的第一个元素,那它肯定是我们要找的;如果mid不等于0,但a[mid]的前一个元素a[mid-1]不等于value,那也说明a[mid]就是我们要找的第一个值等于给定值的元素。

4.2-查找最后一个值等于给定值的元素

      要求数组中存在不重复的数字,现在我们取消这个限制,查找数组中最后一个值等于给定值的元素。

    /**
     * 查询数组中最后一个等于target的数字,返回数组的索引
     *
     * @param array  目前数组
     * @param target 目标值
     * @return 数组下标索引,没有查询到返回-1
     */
    private static int binarySearch03(int[] array, int target) {
        int low = 0;
        int maxIndex = array.length - 1;
        int high = array.length - 1;
        while (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (array[mid] == target) {
                if ((mid == maxIndex) || array[mid + 1] != target) {
                    return mid;
                } else {
                    low = mid + 1;
                }
            }
            if (array[mid] > target) {
                high = mid - 1;
            }
            if (array[mid] < target) {
                low = mid + 1;
            }
        }
        return -1;
    }

       如果a[mid]这个元素已经是数组中的最后一个元素了,那它肯定是我们要找的;如果a[mid]的后一个元素a[mid+1]不等于value,那也说明a[mid]就是我们要找的最后一个值等于给定值的元素。如果我们经过检查之后,发现a[mid]后面的一个元素a[mid+1]也等于value,那说明当前的这个a[mid]并不是最后一个值等于给定值的元素。我们就更新low=mid+1,因为要找的元素肯定出现在[mid+1, high]之间。

4.3-查找第一个大于等于给定值的元素

       对于a[mid]大于等于给定值value的情况,我们要先看下这个a[mid]是不是我们要找的第一个值大于等于给定值的元素。如果a[mid]前面已经没有元素,或者前面一个元素小于要查找的值value,那a[mid]就是我们要找的元素。如果a[mid-1]也大于等于要查找的值value,那说明要查找的元素在[low, mid-1]之间,所以,我们将high更新为mid-1。

  /**
     * 查询数组中查找第一个大于等于给定值的元素,返回数组的索引
     *
     * @param array  目前数组
     * @param target 目标值
     * @return 数组下标索引,没有查询到返回-1
     */
    private static int binarySearch04(int[] array, int target) {
        int low = 0;
        int high = array.length - 1;
        while (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (array[mid] >= target) {
                if ((mid == 0) || array[mid - 1] < target) {
                    return mid;
                } else {
                    high = mid - 1;
                }
            } else {
                low = mid + 1;
            }
        }
        return -1;
    }

4.4-查找最后一个小于等于给定值的元素

       对于a[mid]小于等于给定值value的情况,我们要先看下这个a[mid]是不是我们要找的最后一个值小于等于给定值的元素。如果a[mid]后面已经没有元素,或者后面一个元素大于要查找的值value,那a[mid]就是我们要找的元素。如果a[mid+1]也小于等于要查找的值value,那说明要查找的元素在[mid+1, high]之间,所以,我们将low更新为mid+1。

    /**
     * 查询数组中查找最后一个小于等于给定值的元素,返回数组的索引
     *
     * @param array  目前数组
     * @param target 目标值
     * @return 数组下标索引,没有查询到返回-1
     */
    private static int binarySearch05(int[] array, int target) {
        int low = 0;
        int maxIndex = array.length - 1;
        int high = array.length - 1;
        while (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (array[mid] <= target) {
                if ((mid == maxIndex) || array[mid + 1] > target) {
                    return mid;
                } else {
                    low = mid + 1;
                }
            }

        }
        return -1;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1303994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

​pathlib --- 面向对象的文件系统路径​

3.4 新版功能. 源代码 Lib/pathlib.py 该模块提供表示文件系统路径的类&#xff0c;其语义适用于不同的操作系统。路径类被分为提供纯计算操作而没有 I/O 的 纯路径&#xff0c;以及从纯路径继承而来但提供 I/O 操作的 具体路径。 如果以前从未用过此模块&#xff0c;或不确定…

1、springboot项目运行报错

问题1&#xff1a;获取不到配置文件的参数 我的配置文件获取的参数如下&#xff1a; public class Configures{Value("${configmdm.apk.apkName}")private static String apkName;private void setApkName(String apkName) {Configures.apkName apkName;}private …

k8s详细教程(一)

—————————————————————————————————————————————— 博主介绍&#xff1a;Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 &#x1f345;文末获取源码…

OpenSSL 编程指南

目录 前言初始化SSL库创建SSL 上下文接口(SSL_CTX)安装证书和私钥加载证书(客户端/服务端证书)加载私钥/公钥加载CA证书设置对端证书验证例1 SSL服务端安装证书例2 客户端安装证书创建和安装SSL结构建立TCP/IP连接客户端创建socket服务端创建连接创建SSL结构中的BIOSSL握手服务…

数据结构基础介绍

一.起源及重要性 1968 年&#xff0c;美国的高德纳 Donakl E . Kn uth 教授在其所写的《 计算机程序艺术》第一卷《基本算法 》 中&#xff0c;较系统地阐述了数据的逻辑结构和存储结构及其操作&#xff0c; 开创了数据结构的课程体系 &#xff0c;数据结构作为一门独立的…

基于单片机的定时插座在智能家居中的应用

近年来&#xff0c;随着科学技术的发展迅速&#xff0c;人们对智能化的要求越来越高。越来越多的智能化产品进入千家万户&#xff0c;如电脑电视、扫地机器人、智能空气净化器等。这些家居电器和电子产品大都需要连接电源&#xff0c;为满足多种用电器的正常使用&#xff0c;延…

LeetCode力扣每日一题(Java):58、最后一个单词的长度

一、题目 二、解题思路 1、我的思路 先将字符串转换成字符数组 由于我们需要获取最后一个单词的长度&#xff0c;所以我们从后往前遍历字符数组 我们还需判断所遍历的字符是不是字母&#xff0c;即判断每个字符对应的ASCII值即可&#xff0c;用计数器count来储存单词长度 …

sudo -i 和 sudo -s

一、sudo xxx 以root权限执行单条命令 二、sudo -i 进入一个持续的root环境&#xff0c;以root权限执行命令&#xff0c;但并不是切换到root用户 三、sudo -s 也是进入一个持续的root环境&#xff0c;以root权限执行命令&#xff0c;和sudo -i的区别是保存了原来普通用…

记录 DevEco 开发 HarmonyOS 应用开发问题记录 【持续更新】

HarmonyOS 应用开发问题记录 HarmonyOS 应用开发问题记录一、预览器无法成功运行?如何定位预览器无法编译问题? 开发遇到的问题 HarmonyOS 应用开发问题记录 一、预览器无法成功运行? 大家看到这个是不是很头疼? 网上能看到许多方案,基本都是关闭一个配置 但是他们并…

在线课堂知识付费小程序源码系统 开发组合PHP+MySQL:用手机随时随地地学习,讲师亲自在线授业解惑 带安装部署教程

近年来&#xff0c;人们对于学习的需求也日益增加。传统的课堂教学已经无法满足人们的学习需求&#xff0c;而在线课堂则能够让人们随时随地地进行学习。同时&#xff0c;随着知识付费的兴起&#xff0c;越来越多的讲师也愿意将自己的知识和经验分享给更多的人。因此&#xff0…

【QT入门】基础知识

一.认识Qt qt是一套应用程序开发库&#xff0c;与MFC不同是跨平台的开发类库&#xff0c;主要用来开发图形界面。完全面向对象容易扩展。 优点&#xff1a;1.封装性强&#xff0c;简单易学 2.跨平台 3.独立编译为本地代码 二.qt工程 1.常见的工程文件有这两种…

PDF文件的限制编辑,如何设置?

想要给PDF文件设置一个密码防止他人对文件进行编辑&#xff0c;那么我们可以对PDF文件设置限制编辑&#xff0c;设置方法很简单&#xff0c;我们在PDF编辑器中点击文件 – 属性 – 安全&#xff0c;在权限下拉框中选中【密码保护】 然后在密码保护界面中&#xff0c;我们勾选【…

DevEco Studio 生成HPK文件

DevEco Studio 生成HPK文件 一、安装环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、生成HPK文件 生成的HPK文件存放在entry文件夹下。下图是未生成HPK的样式。 生成HPK&#xff1a;菜单Build->Build Hap(s)/APP(s)->Build Hap(s)…

JavaFx实现图片轮播(二)

上一篇轮播文章发布后&#xff0c;很多人私信我能不能像网页效果一样显示轮播图呢&#xff1f; 那么本篇文章就给大家上实现代码&#xff0c;好了废话不多说&#xff0c;代码如下&#xff1a; fxml文件&#xff1a; <?xml version"1.0" encoding"UTF-8&qu…

MySQL InnoDB Replication部署方案与实践

1. 概述 MySQL Innodb ReplicaSet 是 MySQL 团队在 2020 年推出的一款产品&#xff0c;用来帮助用户快速部署和管理主从复制&#xff0c;在数据库层仍然使用的是主从复制技术。 ReplicaSet 主要包含三个组件&#xff1a;MySQL Router、MySQL Server 以及 MySQL Shell 高级客户…

酷开科技多维度赋能营销,实力斩获三项大奖

在数智化新阶段、广告新生态、传播新业态的背景下&#xff0c;“第30届中国国际广告节广告主盛典暨网易传媒态度营销峰会”于11月18日在厦门国际会展中心盛大举行。来自全国的品牌方、战略决策者、媒体平台和品牌服务机构等汇聚一堂。在50000&#xff0b;现场观众和数千万线上观…

基于SpringBoot的就业信息管理系统设计与实现(源码+数据库+文档)

摘 要 在新冠肺炎疫情的影响下&#xff0c;大学生的就业问题已经变成了一个引起人们普遍重视的社会焦点问题。在这次疫情的冲击之下&#xff0c;大学生的就业市场的供求双方都受到了不同程度的影响&#xff0c;大学生的就业情况并不十分乐观。目前&#xff0c;各种招聘平台上…

C语言经典错误总结(一)

注&#xff1a;本文是结合《C陷阱和缺陷》所写&#xff01; 一.和 我们都知道在C语言中表示赋值操作符&#xff0c;表示比较&#xff0c;那么你知道为啥单等号为&#xff0c;双等号为比较吗&#xff1f; 这里扩展下&#xff1a;因为在C语言中赋值操作符相对于比较符号较常出…

【EI征稿中|JPCS独立出版】第七届机械、电气与材料应用国际学术会议(MEMA 2024)

第七届机械、电气与材料应用国际学术会议&#xff08;MEMA 2024&#xff09; 2024 7th International Conference on Mechanical, Electrical and Material Application (MEMA 2024) 2024年2月23-25日 长沙 MEMA会议属一年一度的国际学术盛会。因其影响力及重要性&am…

刷题第四十天 198.打家劫舍 213.打家劫舍Ⅱ 337. 打家劫舍Ⅲ

class Solution:def rob(self, nums: List[int]) -> int:#dp 偷到第i个房间&#xff0c;最多偷了多少钱#dp[i] max(dp[i - 1], dp[i - 2] nums[i])if len(nums) 1:return nums[0]if len(nums) 2:return max(nums[0], nums[1])dp [0] * (len(nums))dp[0] nums[0]dp[1] …