首页 > 编程语言 >Java学习—二分法查找(一)

Java学习—二分法查找(一)

时间:2023-11-20 23:01:03浏览次数:38  
标签:Java target nums int mid 二分法 查找 low

1、二分查找(binary search)

二分查找(binary search),也称折半搜索,是一种在 有序数组查找某一特定元素 的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

Java学习—二分法查找(一)_搜索

  • 时间复杂度:折半搜索每次把搜索区域减少一半,时间复杂度为O(log n)。(n代表集合中元素的个数)
  • 空间复杂度: O(1)。虽以递归形式定义,但是尾递归,可改写为循环。


动图演示

Java学习—二分法查找(一)_搜索_02

二分查找

2、代码描述

递归

int binarysearch(int array[], int low, int high, int target) {
    if (low > high) return -1;
    int mid = low + (high - low) / 2;
    if (array[mid] > target)
        return binarysearch(array, low, mid - 1, target);
    if (array[mid] < target)
        return binarysearch(array, mid + 1, high, target);
    return mid;
}

非递归(while循环)

int bsearchWithoutRecursion(int a[], int key) {
    int low = 0;
    int high = a.length - 1;
    while (low <= high) {
        int mid = low + (high - low) / 2;
        if (a[mid] > key)
            high = mid - 1;
        else if (a[mid] < key)
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}

3、二分查找中值的计算

这是一个经典的话题,如何计算二分查找中的中值?大家一般给出了两种计算方法:

  • 算法一: mid = (low + high) / 2
  • 算法二: mid = low + (high – low)/2

乍看起来,算法一简洁,算法二提取之后,跟算法一没有什么区别。但是实际上,区别是存在的。算法一的做法,在极端情况下,(low + high)存在着溢出的风险,进而得到错误的mid结果,导致程序错误。而算法二能够保证计算出来的mid,一定大于low,小于high,不存在溢出的问题。

4、二分查找法的缺陷

二分查找法的O(log n)让它成为十分高效的算法。不过它的缺陷却也是那么明显的。就在它的限定之上:必须有序,我们很难保证我们的数组都是有序的。当然可以在构建数组的时候进行排序,可是又落到了第二个瓶颈上:它必须是数组。

数组读取效率是O(1),可是它的插入和删除某个元素的效率却是O(n)。因而导致构建有序数组变成低效的事情。

解决这些缺陷问题更好的方法应该是使用二叉查找树了,最好自然是自平衡二叉查找树了,既能高效的(O(n log n))构建有序元素集合,又能如同二分查找法一样快速(O(log n))的搜寻目标数。


5、练习题1

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

https://leetcode.cn/problems/search-insert-position/?envType=study-plan-v2&envId=top-100-liked

</>代码

class Solution {
    public int searchInsert(int[] nums, int target) {
        int n = nums.length;
        int left=0,right=n-1;
        while(left<=right){
            // int mid = (left+right)/2;
            int mid = left + (right - left)/2;
            
            // 目标数值在中间值 右边
            if(target > nums[mid]){
                left = mid+1;
            // 目标数值在中间值 左边
            } else if(target < nums[mid]){
                right = mid-1;
            }else {
                return mid;
            }
        }
        return left;
    }
}

6、练习题2

给定一个 元素升序的、无重复数字的整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标(下标从 0 开始),否则返回 -1

数据范围:Java学习—二分法查找(一)_数组_03 , 数组中任意值满足 Java学习—二分法查找(一)_二分查找_04

进阶:时间复杂度 Java学习—二分法查找(一)_数组_05 ,空间复杂度 Java学习—二分法查找(一)_二分查找_06


示例1

输入:

[-1,0,3,4,6,10,13,14],13

返回值:

6

说明:

13 出现在nums中并且下标为 6

示例2

输入:

[],3

返回值:

-1

说明:

nums为空,返回-1

</>代码

import java.util.*;
public class Solution {
   //nums是数组,target是目标值
    public int search (int[] nums, int target) { 
        //定义了target在[left,right]区间内
        int left = 0;
        int right = nums.length-1;
       //数组从小到大排序
        while(right>=left){
            //定义中间值的下角标
            int middle = left + ((right-left)/2);
            //如果中间值大于目标值,目标值在左半部分,下一轮二分查找[left,middle-1]
            if (nums[middle] > target){
                right = middle -1;
            //如果中间值小于目标值,目标值在右半部分,下一轮二分查找[middle+1,right]
            }else if(nums[middle] < target){
                left = middle + 1;   
            //如果左右两边都没有,那就是中间值
            }else {
                return middle;
            } 
        }
      //没有找到目标值,返回-1
        return -1;
    }
}


7、练习题3

给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。

1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于

如输入[2,4,1,2,7,8,4]时,会形成两个山峰,一个是索引为1,峰值为4的山峰,另一个是索引为5,峰值为8的山峰,如下图所示:

Java学习—二分法查找(一)_二分查找_07

示例1

输入:

[2,4,1,2,7,8,4]

返回值:

1

说明:

4和8都是峰值元素,返回4的索引1或者8的索引5都可以

示例2

输入:

[1,2,3,1]

返回值:

2

说明:

3 是峰值元素,返回其索引 2

</>代码





标签:Java,target,nums,int,mid,二分法,查找,low
From: https://blog.51cto.com/u_15520037/8492053

相关文章

  • java 接口
    packagenet.elaina.interface01;publicabstractclassAnimal{privateStringname;privateintage;publicAnimal(){}publicAnimal(Stringname,intage){this.name=name;this.age=age;}/***......
  • Java Word 转 pdf
    最近项目需要做在线预览文档功能,要求对word文档后台转为pdf,遇到了很多问题,因此记录一下。网上有很多将Word转换成PDF的方式,这里我试了几种比较简单的方式:POI、aspose、spire和documents4j。1、POIPOI是Apache下的一个Java类库,可以帮助我们实现Java与各种Office格式文件的互相转......
  • JAVA冒泡排序
    //冒泡排序publicclassDemo05{publicstaticvoidmain(String[]args){int[]arr={4,1,5,2,3};for(inti=0;i<arr.length-1;i++){//外循环:控制比较轮数(数组长度-1)i:0,1,2,3for(intj=0;j<arr.length-1......
  • JavaWeb--SqlSessionFactory工具类抽取
    代码优化 Stringresource="mybatis-config.xml";InputStreaminputStream=Resources.getResourceAsStream(resource);SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);//2.2获取SqlSession对象SqlSessionsqlSession=......
  • java抽象类和抽象方法
    ......
  • java 继承
    继承的特点Java只支持单继承,不支持多继承,但支持多层继承。单继承:一个子类只能继承一个父类不支持多继承:子类不能同时继承多个父类多层继承:子类A继承父类B,父类B可以继承父类C每一个类都直接或者间接的继承于Object......
  • JavaSE面试题02:单例设计模式
    单例模式来源:https://www.runwsh.com/archives/biitngg1f7s00001.什么事Singleton?Singleton:在Java中即指单例设置模式,探视软件开发最常用的设置模式之一通俗解释:单例模式单:唯一例:实例单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式......
  • Java登陆第十天——JDBC(二)
    ResultSet接口常用方法ResultSet存放的是DQL查询结果的结果集。常用方法如下:方法类型描述booleannext()throwsSQLException普通方法指针移动到下一行(没有下一行返回false)intgetInt(StringcolumnLabel)throwsSQLException普通方法根据列名获取行Str......
  • 学习JavaScript的第一天
    JavaScript概述JavaScript的介绍js属于一门面向对象的编程语言属于跨平台面向对象(oop)以对象方式实现所有的功能跨平台:js代码不论是在什么样的操作系统上执行结果都是一样JavaScript发展史ECMA根据微软与网景配合设计了JS的语法标准(ECMAScript简称叫做ES)ES存在很......
  • Windows部署Java环境
    下载Java开发工具包JDK(JavaDevelopmentKit)进入Java官网下载页。找到需要的JDK版本,选择Windows系统,在Downloads下,单击下载链接。双击运行JDK安装包。单击下一步,然后修改安装目录,再单击下一步。等待安装完成,单击关闭。修改环境变量,将JDK安装目录下的bin目录,加入到系统变量......