二分查找算法

二分查找算法

条件:二分查找法只适用于从有序的队列中进行查找(比如数字和字母等).

1.整数的二分查找
先让我们举个例子,比如给定一个数组a,必须保证数组有序,让我们在数组中查找一个元素,如果有则返回数组的索引,如果没有则返回-1.让我们来写一个方法

public int test(int a[], int target) {
        int l = 0;
        int r = a.length - 1;
        while (l <= r) { // 循环判断,其实就是当 r = l + 1 时跳出循环
            int mid = l + (r - l) / 2;//其实就是 mid = (l + r ) / 2 ,这里这么写就是为了防止mid越界.
            if (a[mid] == target) return mid; 
            else if (a[mid] < target) l = mid + 1; //如果 a[mid] < target ,说明target在a[mid+1]--a[r]之间
            else if (a[mid] > target) r = mid - 1; //如果 a[mid] > target ,说明target在a[l]--a[mid-1]之间
        }
        return -1;//如果循环停止还没有找到,说明该数组中没有该数,所以返回-1.
    }

当然了,这种情况是很少的,让我们再看一个例子,力扣第35题,搜索插入位置:

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-insert-position

这道题很明显和上一个题是有些不同的,这个时候我们应该怎么办呢?
让我们分析一下,如果数组中有这个数,我们还是return mid,这个是没有问题的,那如果在数组中没有这个数,我们就不能return -1了,那我们应该return什么呢?

让我们先看看第一题的循环是过程是样子的,我们在while语句中做一个输出(输出l,r,mid)
在这里插入图片描述
我们可以看到,当结束while循环时,我们最后的 l=5;r=4;mid=5; 所以我们就可以联想到,最后的我们可以return I 就可以了;
让我们来看一看代码:

 public static int test(int a[], int target) {
        int l = 0;
        int r = a.length - 1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (a[mid] == target) return mid;
            else if (a[mid] < target) l = mid + 1;
            else if (a[mid] > target) r = mid - 1;
        }
        return l;
    }

这时候我们就完成了这一道题.如果大家感兴趣,可以拿力扣69题 Sqrt(x) 练习一下这个算法.

2.浮点数的二分查找
浮点数的二分查找解题思路和整数的二分查找的解题思路也是基本相同的.但是还是有一些区别的.

让我们用一个例子来看浮点数的二分查找:
在不使用库函数的情况下,求x的三次方根 . 其中-10000<a<10000;结果保留6位小数.

让我们来看看解题代码

public static double reverse(double x) {
        double a = -10000, b = 10000;//a为x的最小值,b为x的最大值.
        while (b - a > Math.pow(10, -8)) {//在这里为什么要用b - a > Math.pow(10, -8)呢?因为运算结果要保留6位小数,为了严谨,我们在运算的时候保留8位小数.
            double temp = (a + b) / 2;//取中间值
            if (Math.pow(temp, 3) == x) return temp;
            if (Math.pow(temp, 3) > x) b = temp + 1;
            else a = temp - 1;
            System.out.println("left = " + a + ", right = " + b + ", mid = " + temp);
        }
        return a;
    }

最后我们在main方法中调用该方法并传值就可以运行了.

这里给出关于二分查找的条件的模板

 public static void main(String[] args) {
        double a = reverse(10000000);//在这里我们传了10000000,
        System.out.printf("%.6f", a);//"%.6f",让a后面的小数保留6位.
    }
package com.ffyc.easy;

// 二分查找模板
public class BinarySearch {
    //查找某一个数的下标(任意位置)
    public static int search(int[] array, int target) {
        int l = 0;
        int r = array.length - 1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (array[mid] == target) return mid;
            else if (array[mid] < target) l = mid + 1;
            else r = mid - 1;
        }
        return -1;
    }


    //查找某一个数第一次出现的位置
    public static int frist(int[] array, int target) {
        int l = -1;
        int r = array.length;
        while (l + 1 != r) {
            int mid = (l + r) / 2;
            if (array[mid] < target) l = mid;
            else r = mid;
        }
        if (array[r] == target) return r;
        else return -1;
    }

    //查找某一个数最后出现的位置
    public static int end(int[] array, int target) {
        int l = -1;
        int r = array.length;
        while (l + 1 != r) {
            int mid = (l + r) / 2;
            if (array[mid] <= target) l = mid;
            else r = mid;
        }
        return l;
    }

    //查找某一个数的前一个元素
    public static int ffrist(int[] array, int target) {
        int l = -1;
        int r = array.length;
        while (l + 1 != r) {
            int mid = (l + r) / 2;
            if (array[mid] < target) l = mid;
            else r = mid;
        }
        if (array[r] == target) return l;
        else return -1;
    }

    //查找某一个数的后一个元素
    public static int eend(int[] array, int target) {
        int l = -1;
        int r = array.length;
        while (l + 1 != r) {
            int mid = (l + r) / 2;
            if (array[mid] <= target) l = mid;
            else r = mid;
        }
        return r;
    }

   
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值