【手撕数据结构】二分查找(好多细节)

这篇具有很好参考价值的文章主要介绍了【手撕数据结构】二分查找(好多细节)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🌈键盘敲烂,年薪30万🌈

目录

普通版本的二分查找:

right只负责控制边界(少了两次比较):

时间复杂度更稳定的版本:

BSLeftmost:

BSRightmost:


 文章来源地址https://www.toymoban.com/news/detail-752849.html

普通版本的二分查找:

  • 🏸细节1:循环判定条件是left <= right
  • ⭐细节2:mid = (left + right ) >>> 1 原因见代码注释

/***
 * 二分查找的实现 3个版本
 * 时间复杂度:O(longn)
 * 空间复杂度:O(1)
 *
 * 细节1:循环判定条件是left <= right
 * 细节2:mid计算要用 >>> 因为left + right 可能越界
 *      例如:right = Integer.MAX_INT-1 left = 0;
 *      第一轮计算没问题 假设mid < target
 *      left = mid + 1; 这是后left+ right 就超出int的最大范围,变成负数
 *      原因很简单:java没有无符号数,最高位表示符号位,/ 运算是先将补码转原码 >>>位运算是直接再二进制上运算
 */
public class Demo1 {
    public static void main(String[] args) {
        int[] nums = {1,4,6,8,15,76,145};
        int target = 145;
        int index1 = method1(nums, target);
        System.out.println(target + "索引为" + index1);
        System.out.println(target + "索引为" + index2);
    }

    private static int method1(int[] nums, int target) {
        int left = 0, right = nums.length-1;
        while(left <= right){
            //细节 用无符号右移运算符
            int mid = (left + right) >>> 1;
            if(nums[mid] > target){
                right = mid - 1;
            }else if (nums[mid] < target){
                left = mid + 1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

right只负责控制边界(少了两次比较):

  • 改动1:while条件是left < right
  • 改动2:right = nums.length
public class Demo1 {
    public static void main(String[] args) {
        int[] nums = {1,4,6,8,15,76,145};
        int target = 145;
        int index2 = method2(nums, target);
        System.out.println(target + "索引为" + index2);
    }
}
    private static int method2(int[] nums, int target) {
        int left = 0, right = nums.length; //right 只代表有边界,不参与比较
        while(left < right){
            int mid = (left + right) >>> 1;
            if(nums[mid] < target){
                left = mid + 1;
            }else if(nums[mid] > target){
                right = mid;
            }else {
                return mid;
            }
        }
        return -1;
    }

时间复杂度更稳定的版本:

  • 细节:减少了if比较次数
public class Demo1 {
    public static void main(String[] args) {
        int[] nums = {1,4,6,8,15,76,145};
        int target = 145;
        int index3 = method3(nums, target);
        System.out.println(target + "索引为" + index3);
    }
}    
    private static int method3(int[] nums, int target) {
        //这个最牛逼
        //减少循环内的比较次数
        int left = 0, right = nums.length;
        while(1 < right - left){
            int mid = (left + right) >>> 1;
            if(nums[mid] > target){
                right = mid;
            }else{
                left = mid;
            }
        }
        if(nums[left] == target){
            return left;
        }
        return -1;
    }

BSLeftmost:

/**
 *
 * 应用:求成绩排名  求前任
 */
public class Leftmost {
    public static void main(String[] args) {
        int[] nums = {1,2,4,4,4,6,7};
        int target = 3;
        /***
         * params
         * return 找到了 - 返回靠左的下标
         *        没找到 - 返回>target的最靠左下标
         */
        int ans = BSLeftmost(nums, target);
        System.out.println(ans);

    }

    private static int BSLeftmost(int[] nums, int target) {
        int left = 0, right = nums.length -1;
        while(left <= right){
            int mid = (left+right) >>> 1;
            if(target > nums[mid]){
                left = mid + 1;
            } else{
                right = mid - 1;
            }
        }
        return left;
    }
}

BSRightmost:

/**
 *
 * 求后任
 */
public class Rightmost {
    public static void main(String[] args) {
        int[] nums = {1,2,4,4,4,6,7};
        int target = 3;
        /**
         * return 找到了返回下标
         *        没找到返回 <= targer的最靠右索引
         *
         */
        int ans = BSRightmost(nums, target);
        System.out.println(ans);
    }

    private static int BSRightmost(int[] nums, int target) {
        int left = 0, right = nums.length-1;
        while(left <= right){
            int mid = (left + right) >>> 1;
            if(target >= nums[mid]){
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        return left - 1;
    }
}

到了这里,关于【手撕数据结构】二分查找(好多细节)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构-查找(顺序查找与二分查找的讲解与代码实现)

    顺序查找概念:从表的另一端开始,一次将记录的和给定值进行比较,若某个记录的和给定的值相等,则查找成功,反之则查找失败。 ASL:平均查找长度 pi查找概率,ci查找次数 eg:序列1,2,3 查找1的次数为1概率为1/3,2为两次概率1/3,3的次数为3概率1/3  将12

    2024年02月06日
    浏览(58)
  • Python数据结构与算法篇(五)-- 二分查找与二分答案

    1.1 定义         二分查找又称折半查找、二分搜索、折半搜索等,是一种在静态查找表中查找特定元素的算法。         所谓静态查找表,即只能对表内的元素做查找和读取操作,不允许插入或删除元素。         使用二分查找算法,必须保证查找表中存放的是有

    2023年04月20日
    浏览(35)
  • 【数据结构与算法】python实现二分查找

    二分查找 又称折半查找,它是一种效率较高的查找方法 原理:首先,假设表中元素是按升序排列,将表中间位置记录的与查找比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的大于查找,则

    2024年02月05日
    浏览(30)
  • 数据结构和算法之二分法查找

    二分法查找,也称作 二分查找 或 折半查找 ,是一种在有序数组中快速查找特定元素的算法。它采用分治法思想,通过将问题划分为规模更小的子问题,并且通过对子问题的查找来解决原问题。 二分法查找的思路是不断地将数组一分为二,然后判断目标值在哪一部分,进而

    2024年02月09日
    浏览(30)
  • 浙大数据结构第一周01-复杂度3 二分查找

    本题要求实现二分查找算法。 函数接口定义: 其中 List 结构定义如下: L 是用户传入的一个线性表,其中 ElementType 元素可以通过、==、进行比较,并且题目保证传入的数据是递增有序的。函数 BinarySearch 要查找 X 在 Data 中的位置,即数组下标(注意:元素从下标1开始存储)

    2024年02月12日
    浏览(27)
  • C++二分算法(二分查找&二分答案)细节详解

     二分算法可以分为 二分查找 和 二分答案 。 以在一个 升序数组 中查找一个数为例。它每次考察数组当前部分的 中间元素 ,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果

    2024年02月08日
    浏览(35)
  • 「算法」二分查找1:理论&细节

    🎇 个人主页 :Ice_Sugar_7 🎇 所属专栏 :算法详解 🎇 欢迎点赞收藏加关注哦! 这个算法的特点就是: 细节多,出错率高,很容易就写成死循环 有模板,但切记要 在理解的基础上记忆 ,不要死记硬背。有三个模板,一个是本文要讲的 简单模板 ,另外两个分别是 查找左、

    2024年02月20日
    浏览(28)
  • 【数据结构】手撕排序

    🔥 博客主页 : 小羊失眠啦. 🎥 系列专栏 : 《C语言》 《数据结构》 《Linux》 《Cpolar》 ❤️ 感谢大家点赞👍收藏⭐评论✍️ 排序 :所谓排序就是使一串记录,按照其中的某个或某些的大小, 递增或递减 的排列起来的操作。排序算法,就是如何使得记录按照要求

    2024年02月05日
    浏览(33)
  • 【数据结构】手撕顺序表

    顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储; 在数组上完成数据的增删查改。  1,  静态顺序表 :使用 定长数组 存储元素。 2., 动态顺序表 :使用 动态开辟 的数组存储。   静态顺序表只适用于确定知道需要存多少数

    2024年02月11日
    浏览(33)
  • 数据结构之——(手撕)顺序表

    本章会介绍的知识点如下图:                    顺序表的结构:逻辑结构与物理结构都是内存中一块连续开辟的空间,都是11对应的线性结构。 两种定义顺序表的方式代码如下         静态的顺序表         动态的顺序表:          在这两种结构中通常我们是会

    2024年02月11日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包