二分查找 binarySearch

2023-11-12

基本概念

在一串有序数组中(上升或下降)找出一个key值。
• 如果key小于中值,则继续查找左边(上升)或者右边(下降)
• 如果key等于中值,则查找成功
• 如果key大于中值,则继续查找右边(上升)或者左边(下降)

时间复杂度和空间复杂度

时间复杂度: O(nlogn + 1) 空间复杂度: O(1)
关于时间复杂度:
let n be a power of 2. After the first comparison, n/2 elements are left for further search; after the second comparison, (n/2)/2 elements are left. After the kth comparison, n/2^k elements are left for further search. When k = log2n, only one element is left in the array, and you need only one more comparison. Therefore, in the worst case when using the binary search approach, you need log2n+1 comparison to find an element in the sorted array. In the worst case for a list of 1024 (2^10) elements, binary search requires only 11 comparisons, whereas a linear search requires 1023 comparisons in the worst case.
在这里插入图片描述

如何取mid

  • 第一种方法:(left + right) / 2;
  • 第二种方法: left + (right - left) / 2;

第一种方法在left和right都近似int的最大值 2^31 的情况下会出现溢出,所以用第二种方法

Level 1: 一般实现

迭代法


	public static int binarySearchNoneRecursive(int key, int [] input){
		int left = 0;
		int right = input.length -1;
		int mid;
		
		while(left <= right) {
			mid = (left+right)/2;
			if(key == input[mid]) {
				return mid;
			}		
			if(key < input[mid]) {
				right = mid - 1;
			}
			else if (key > input[mid]) {
				left =  mid + 1;
			}			
		}
		
		return -1;
	}

递归法

public static int binarySearchRecursive(int key, int [] input, int left, int right){
		if(right < left)
			return -1;
		
		int mid = left + (right - end) / 2;
	
		if(input[mid] == key) {
			return mid;
		}
		else if(key < input[mid]) {
			return binarySearchRecursive(key, input, left, mid-1);
		}
		else if (key > input[mid]) {
			return binarySearchRecursive(key, input, mid+1, right);
		}
		else {
			return -1;
		}
	}

Level 2: First or Last Position of Target

Last Position of Target

Last Position of Target: 取数组中最后一次出现的target的index, 比如: [1,2,3,3,3,56],取第三个3的下标

public class Solution {
    /**
     * @param nums: The integer array.
     * @param target: Target to find.
     * @return: The first position of target. Position starts from 0.
     */
    public int lastPosition(int[] nums, int target) {
        if (nums.length == 0) {
            return -1;
        }
        int left = 0;
        int right = nums.length -1;
        //这里是left + 1 < right
        //也就是还有两个数的时候退出循环
        while (left + 1 < right) {
            int mid = left + (right - left) / 2;
            
            if (nums[mid] == target) {
          //这里是left = mid,不直接return 因为不确定是否是最后一次出现的位置
          //left=mid 把二分的范围向右收缩,这样可以找到最后一次出现的target
                left = mid;
            }
            else if (target < nums[mid]) {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
    	
    	//退出循环的时候还有两个数,所以要分别判断是否是target
    	//因为是找最后一次出现的位置,所以先判断right
        if (nums[right] == target) {
            return right;
        }
        
        if (nums[left] == target) {
            return left;
        }
        
        return -1;
    }
}

First Position of Target

First Position of Target: 取数组中第一次出现的target的index, 比如: [1,2,3,3,3,56],取第一个3的下标

public class Solution {
    /**
     * @param nums: The integer array.
     * @param target: Target to find.
     * @return: The first position of target. Position starts from 0.
     */
    public int binarySearch(int[] nums, int target) {
        if (nums.length == 0) {
            return -1;
        }
        
        int left = 0;
        int right = nums.length -1;
         //这里是left + 1 < right
        //也就是还有两个数的时候退出循环
        while (left + 1 < right) {
            int mid = left + (right - left) / 2;
            
          //这里是right=mid,不直接return 因为不确定是否是第一次出现的位置
          //right=mid 把二分的范围向左收缩,这样可以找到第一次出现的target
            if (nums[mid] == target) {
                right = mid;
            }
            else if (target < nums[mid]) {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
        
        //退出循环的时候还有两个数,所以要分别判断是否是target
    	//因为是找第一次出现的位置,所以先判断left
        if (nums[left] == target) {
            return left;
        }        
        if (nums[right] == target) {
            return right;
        }
        
        return -1;
    }
}

Level 3: Find Minimum in Rotated Sorted Array

Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:

  • [4,5,6,7,0,1,2] if it was rotated 4 times.
  • [0,1,2,4,5,6,7] if it was rotated 7 times.

Notice that rotating an array [a[0], a[1], a[2], …, a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], …, a[n-2]].
Given the sorted rotated array nums, return the minimum element of this array.

Example 1:
Input: nums = [3,4,5,1,2]
Output: 1
Explanation: The original array was [1,2,3,4,5] rotated 3 times.
Example 2:

Input: nums = [4,5,6,7,0,1,2]
Output: 0
Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.
Example 3:

Input: nums = [11,13,15,17]
Output: 11
Explanation: The original array was [11,13,15,17] and it was rotated 4 times.

/*
原理是利用二分法:
对于任意一个旋转过的数组:
Example: 6,7,1,2,3,4,5
如果mid的值大于right的值 (Example中的 2大于5) 则说明最小值在右边
如果mid的值小于right的值 则说明最小值在左边
如果mid的左边的值比mid大,mid右边的值也比mid大,则说明mid就是最小值 (3,1,2)
*/


class Solution {
    public int findMin(int[] nums) {
        if (nums.length == 1) {
            return nums[0];
        }

        int left = 0;
        int right = nums.length - 1;

        while (left <= right) {
            int mid = left + (right - left)/2;

            //处理mid等于第一个元素时的情况
            if (mid == 0) {
                return nums[0] < nums[1] ? nums[0] : nums[1];
            }
            //处理mid等于最后一个元素时的情况
            if (mid == nums.length - 1) {
                return nums[nums.length-1] < nums[nums.length - 2] ? nums[nums.length - 1] : nums[nums.length - 2];
            }

            //如果mid的左边的值比mid大,mid右边的值也比mid大,则说明mid就是最小值 (3,1,2)
            if (nums[mid - 1] > nums[mid] && nums[mid + 1] > nums[mid]) {
                return nums[mid];
            }
            //如果mid的值大于right的值, 则说明最小值在右边
            else if (nums[mid] > nums[right]) {
                left = mid + 1;
            }
            //其余情况在左边 (mid的值小于right的值 则说明最小值在左边)
            else {
                right = mid - 1;
            }
        }

        return nums[0];
    }
}

Level 4: Search in Rotated Sorted Array

You are given an integer array nums sorted in ascending order (with distinct values), and an integer target.
Suppose that nums is rotated at some pivot unknown to you beforehand (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).
If target is found in the array return its index, otherwise, return -1.

Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
Example 3:

Input: nums = [1], target = 0
Output: -1

/*
采用二分法:
Example    6 7 8 9 1 2 3 4 5
在中间切一刀
如果nums[mid] > nums[left],则说明left到mid有序(递增顺序)
    判断 target是否在 left到mid之间,如果在则说明在左边,如果不在说明在右边

如果 nums[mid] < nums[left], 则说明mid到right有序(递增顺序)
    判断 target是否在 mid到right之间,如果在则说明在右边,如果不在说明在左边
*/

class Solution {
    public int search(int[] nums, int target) {
        if (nums.length == 0) {
            return -1;
        }
        int left = 0;
        int right = nums.length - 1;

        while (left + 1< right) {
            int mid = left + (right - left) / 2;
            
            //如果nums[mid] > nums[left],则说明left到mid有序(递增顺序)
            if (nums[mid] > nums[left]) {
                // 判断 target是否在 left到mid之间
                if (target >= nums[left] && target <= nums[mid]) {
                    right = mid;
                }
                else {
                    left = mid;
                }
            }
            //如果 nums[mid] < nums[left], 则说明mid到right有序(递增顺序)
            else {
                // 判断 target是否在 mid到right之间
                if (target >= nums[mid] && target <= nums[right]) {
                    left = mid;
                }
                else {
                    right = mid;
                }
            }
        }

        if (nums[left] == target) {
            return left;
        }
        if (nums[right] == target) {
            return right;
        }

        return -1;
    }
}

Level 5: Find K Closest Elements

Level 6: Wood Cut

Given n pieces of wood with length L[i] (integer array). Cut them into small pieces to guarantee you could have equal or more than k pieces with the same length. What is the longest length you can get from the n pieces of wood? Given L & k, return the maximum length of the small pieces.

Example 1
Input:
L = [232, 124, 456]
k = 7
Output: 114
Explanation: We can cut it into 7 pieces if any piece is 114cm long, however we can’t cut it into 7 pieces if any piece is 115cm long.
Example 2

Input:
L = [1, 2, 3]
k = 7
Output: 0
Explanation: It is obvious we can’t make it.


/*基于答案值域的二分法。
木头长度的范围在 1 到 max(L),在这个范围内二分出一个长度 length,
然后看看以这个 wood length 为前提的基础上,能切割出多少木头,
如果少于 k 根,说明要短一些才行,如果多余 k,说明可以继续边长一些。
*/

public class Solution {
    /**
     * @param L: Given n pieces of wood with length L[i]
     * @param k: An integer
     * @return: The maximum length of the small pieces
     */
    public int woodCut(int[] L, int k) {
        int maxL = 0;
        for (int i = 0; i < L.length; i++) {
            maxL = Math.max(maxL, L[i]);
        }
        
        int left = 1;
        int right = maxL;
        int result = 0;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            int temp = count(mid, L);
            
            if (temp >= k) {
                result = mid;
                left = mid + 1;
            }
            else {
                right = mid - 1;
            }
        }
        
        return result;
    }
    
    public int count(int mid, int [] L) {
        int sum = 0;
        for (int i = 0; i < L.length; i++) {
            sum += L[i] / mid;
        }
        
        return sum;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

二分查找 binarySearch 的相关文章

  • Mac os使用git,不依赖Xcode

    说明 后来发现使用mac的命令行开发者工具很香 于是又删除了下文安装的git 直接点击下图的 安装 来获取命令行开发者工具 安装路径是 Library Developer CommandLineTools 包含了git gcc g make
  • import com.google.common.* 出错,找不到

    一 问题 在启动项目的时候 import com google common base Preconditions 报错 找不到这个类 二 解决 要引入guavar依赖 Guava 中文是石榴的意思 该项目是 Google 的一个开源项目
  • JavaWeb 相关问题汇总:

    我是目录 1 输入 URL 后发生了什么事情 如何定位服务资源 2 如何接收 HTTP 请求数据 3 ajax有什么作用 4 Filter 过滤器 5 tomcat 1 输入 URL 后发生了什么事情 如何定位服务资源 通过IP找到主机 通
  • 华为OD2023(A卷)基础题27【找数字、找等值元素】

    华为OD机试 找数字 找等值元素 找数字 给一个二维数组nums 对于每一个元素num i 找出距离最近的且值相等的元素 输出横纵坐标差值的绝对值之和 如果没有等值元素 则输出 1 输入描述 输入第一行为二维数组的行 输入第二行为二维数组的
  • java通过经纬度获取区间

    引入依赖
  • python语言程序设计实践教程答案上海交通大学陈东_《C语言程序设计》蔺德军 主著【摘要 书评 在线阅读】-苏宁易购图书...

    商品参数 作者 蔺德军 主著 出版社 辽宁大学出版社 出版时间 2015 11 01 ISBN 9787121274220 版权提供 辽宁大学出版社 基本信息 书名 C语言程序设计上机实验与习题解答 定价 29 00元 售价 18 6元 便
  • 卡内基梅隆大学(CMU),那些经受住时间考验的机器学习论文–第二弹:动态主题模型

    这次 我们要解释一种典型的机器学习算法 动态主题模型 Dynamic Topic Model 概率主题模型和概率图模型是每个做文本挖掘的学者的必学课题 其中最常见的主题模型是隐含狄利克雷分布 LDA 当然 本文的动态主题模型也是主题模型的一
  • Mysql group by 与order by 一起使用

    项目中遇到这样的要求 从数据表里查出每台机器的最后一次链接时间 必须group by机器id order by connect time SELECT c d equipment type FROM ms gateway connect c
  • C++中float和double的比较

    在c 开发中 double或者float类型判断相等性不能简单的用等于符号 进行 一般会采用如下方式进行判断 static inline bool DoubleEqual double a double b return fabs a b
  • Log4j学习笔记

    Log4j学习笔记 1 入门实例 2 Log4j基本使用方法 2 1 定义配置文件 2 2 在代码中使用Log4j 2 3 日志级别 本文参考https blog csdn net u013870094 article details 79
  • 实战--Kafka学习(二)

    问题导读1 Kafka工作包含哪些流程 2 为防止log文件过大导致数据定位效率低下 kafka引入了什么 3 Kafka生产者分区的原因和原则是什么 4 Kafka数据可靠性是如何保证的 3 1 Kafka工作流程及文件存储机制Kafka
  • 哈希及其应用(字典,加密等)

    一 名词说明 Hash 一般翻译做散列 杂凑 或音译为哈希 是把任意长度的输入 又叫做预映射pre image 通过散列算法变换成固定长度的输出 该输出就是散列值 这种转换是一种压缩映射 也就是 散列值的空间通常远小于输入的空间 不同的输入
  • kafka学习

    链接1 Kafka入门教程 香菜 的博客 CSDN博客 链接2 https mbd baidu com ug share mbox 4a83aa9e65 share product smartapp tk d716b5f663babe030
  • mysql函数及关键字使用

    collect set collect set col 函数只接受 基本数据类型 它的主要作用是将某字段的值进行去重汇总 产生array类型字段 MySQL中concat函数 连接字符串 MySQL中concat函数 使用方法 concat
  • java语法基础练习

    1 阅读示例 EnumTest java 并运行 分析结果 代码 public class EnumTest public static void main String args Size s Size SMALL Size t Size
  • MSP432学习笔记:IAR的环境配置(官方demo程序的测试)

    近来入手一块MSP432 折腾了一天 终于把官方demo程序导入IAR 可以愉快的写代码了 以下是我个人的解决办法 首先 如果要使用IAR对TI的单片机进行开发 首先要下载对应的单片机型号的MSPWARE 本人目前使用的是TI的MSP432
  • python实现的一些方法,可以直接拿来用的那种

    1 日期生成 很多时候我们需要批量生成日期 方法有很多 这里分享两段代码 获取过去 N 天的日期 import datetime def get nday list n before n days for i in range 1 n 1
  • 梯度下降算法

    下面这篇文章讲的非常不错 https www jianshu com p c7e642877b0e 转载于 https www cnblogs com lvchaoshun p 11403808 html

随机推荐

  • 【网络】协议定制+序列化/反序列化

    为什么要序列化 如果光看定义很难理解序列化的意义 那么我们可以从另一个角度来推导出什么是序列化 那么究竟序列化的目的是什么 其实序列化最终的目的是为了对象可以跨平台存储 和进行网络传输 而我们进行跨平台存储和网络传输的方式就是IO 而我们的
  • leetcode刷题(5)

    各位朋友们 大家好 今天是我leedcode刷题的第五篇 我们一起来看看吧 文章目录 栈的压入 弹出序列 题目要求 用例输入 提示 做题思路 代码实现 C语言代码实现 Java代码实现 最小栈 题目要求 用例输入 提示 做题思路 代码实现
  • eclipse中使用Install New software下载资源超时解决

    问题 使用eclipse中提供的Help菜单 Install New software 已填入正确的链接地址 但是在下载过程中出现错误 Some sites could not be found See the error log for
  • 宝塔面板升级踩坑:ImportError: class/PluginLoader.so: undefined symbol: PyImport_GetModule

    今天在宝塔面板升级了PHP8 但是站点的PHP版本选择仍然没有PHP8以上的版本 百度了一下说是要升级宝塔面板 于是在面板首页右上角进行了升级 结果升级后发现安全入口无法打开 于是用ssh登录服务器 执行命令 etc init d bt d
  • 推荐 20 款 IDEA 主题!

    官方对主题模块的介绍 作为一名开发人员 您需要使用大量文本资源 编辑器中的源代码 搜索结果 调试器信息 控制台输入和输出等等 颜色和字体样式用于格式化这个文本 并帮助您更好地理解它一目了然 个人感觉 每天我们大半的时间都是在跟代码打交道 时
  • Vue前端代码风格指南超级详细

    本文仅作日常项目开发中的知识补充 不必按顺序阅读 如果已经知悉 请跳过 一 命名规范 现有常用的命名规范 camelCase 小驼峰 首字母小写 PsscalCase 大驼峰 首字母大写 kebab case 短横线连接式 Snake 下划
  • VSCode好用的插件

    文章目录 前言 1 Snippet Creator easy snippet 自定义代码 2 Indent Rainbow 代码缩进 3 Chinese Simplified Language Pack 中文包 4 Path Intelli
  • react项目配置 @ 为src根目录

    前置 修改jsconfig json文件 compilerOptions jsx react experimentalDecorators true baseUrl paths src 1 原生create react app 的情况 若已
  • 16、什么是拟牛顿法(Quasi-Newton Methods)?

    拟牛顿法是求解非线性优化问题最有效的方法之一 于20世纪50年代由美国Argonne国家实验室的物理学家W C Davidon所提出来 Davidon设计的这种算法在当时看来是非线性优化领域最具创造性的发明之一 不久R Fletcher和M
  • CSharp: iTextSharp 5.13.2 create pdf

    using System using System Collections Generic using System Web using System Web UI using System Web UI WebControls using
  • 超级卡哇伊的登录框

    css margin 0 padding 0 box sizing border box a color 6a6a6a text decoration none body background color 96c6e2 box displa
  • multi-view clustering指标

    几种 multi view clustering 的指标代码 介绍见 1 3 4 6 有实现 Matching Assignment 由于聚类没有类顺序 而有些指标用到 ground truth labels 如 accuracy 等分类指
  • 操作系统识别

    1 操作系统指纹 操作系统的识别有很多方法 大多跟TCP IP协议有关 操作系统对TCP IP的实现 都是严格遵循RFC标准的 问题RFC标准仅描述了TCP IP的基本要求 并没有对所有内容形成统一的行业标准 于是各操作系统厂商在实现了TC
  • Free FTP Clients 客户端:WinSCP 的 3 种版本 (**)

    安装版 便携版 WinSCP Scripting 自动化 字符编码问题 在跨平台进行文件共享时 涉及到字符的编码问题 采用 ftp一般都可以解决乱码问题 而共享网络文件夹一般不能 ftp的一个问题是 当连接中断时 会造成文件的残缺 有些 f
  • Qt目录树实现

    1 View 根据参考资料 4 的说明 可以使用QTreeView或者QListView来显示目录树 2 Model 2 1 文件系统Model 实现一个系统文件目录树模式 可以选择使用QFileSystemModel或者QDirModel
  • java.lang.ClassCastException: cn.hutool.json.JSONObject cannot be cast toXXXX

    java lang ClassCastException cn hutool json JSONObject cannot be cast toXXXX 除了网上常见解决方案以外 也存在另一种可能导致的类型转换异常 例如 当使用JSONUt
  • Python中的条件循环

    1 if条件 1 1 语法规则 if的语法 if confident 条件判断为布尔型 doing thing true时完成的动作 else doing thing false时完成的动作 1 2 示例 if else 图 1 if示例
  • QT程序发布

    用Release版本运行 将生成的exe文件拷贝到一个空文件夹中 找到QT的cmd窗口 在cmd窗口中 用 cd 命令 进入第一步中建立的空文件夹中 运行命令windeployqt exe文件 将程序需要的库文件都导入该文件中 将整个文件夹
  • Python毕业设计基于django的企业人力资源管理系统

    文末获取资源 收藏关注不迷路 文章目录 一 项目介绍 二 主要使用技术 三 研究内容 四 核心代码 五 文章目录 一 项目介绍 在互联网信息技术时代中 企业管理更多的是使用管理系统进行智能化控制 提高单位的核心竞争力 适应快节奏的生产活动
  • 二分查找 binarySearch

    二分查找 binarySearch 基本概念 时间复杂度和空间复杂度 如何取mid Level 1 一般实现 迭代法 递归法 Level 2 First or Last Position of Target Last Position of