二分查找练习

如何编程实现“求一个数的平方根”?要求精确到小数点后 6 位。

先把求小数问题转换成求整数问题, 精度为1, 再除以10^6, 转换成小数

  1. 先把要求的数 n*1012
  2. 二分法求出这个数 n*1012 的平方根整数x, 要求 x2<=n*1012 并且 (x+1)2> n*1012
  3. 将 x / 106 得到精确到小数点后6位的平方根
	/**
     * 求一个数的平方根
     * @param value 数
     * @param accuracy 小数位数
     * @return
     */
    public static double square(double value, int accuracy){
        //把它转换成求整数问题, 精度为1, 再转换为小数
        double bigValue = value * Math.pow(10, accuracy * 2);
        int low = 0;
        int high = (int) Math.ceil(bigValue);

        //二分法查找i i^2<bigValue&&(i+1)^2>bigValue
        while(low <= high){
            int mid = ((high - low) >> 1) + low;
            if (Math.pow(mid, 2) <= bigValue && Math.pow(mid + 1, 2) > bigValue) {
                return mid / Math.pow(10, accuracy);
            }else if(Math.pow(mid, 2) > bigValue){
                high = mid - 1;
            }else{
                low = mid + 1;
            }
        }
        return -1D;
    }

如何在 1000 万个整数中快速查找某个整数?

这个问题并不难。我们的内存限制是 100MB,每个数据大小是 8 字节,最简单的办法就是将数据存储在数组中,内存占用差不多是 80MB,符合内存的限制。借助今天讲的内容,我们可以先对这 1000 万数据从小到大排序,然后再利用二分查找算法,就可以快速地查找想要的数据了。

看起来这个问题并不难,很轻松就能解决。实际上,它暗藏了“玄机”。如果你对数据结构和算法有一定了解,知道散列表、二叉树这些支持快速查找的动态数据结构。你可能会觉得,用散列表和二叉树也可以解决这个问题。实际上是不行的。

虽然大部分情况下,用二分查找可以解决的问题,用散列表、二叉树都可以解决。但是,我们后面会讲,不管是散列表还是二叉树,都会需要比较多的额外的内存空间。如果用散列表或者二叉树来存储这 1000 万的数据,用 100MB 的内存肯定是存不下的。而二分查找底层依赖的是数组,除了数据本身之外,不需要额外存储其他信息,是最省内存空间的存储方式,所以刚好能在限定的内存大小下解决这个问题。

如果数据使用链表存储,二分查找的时间复杂就会变得很高,那查找的时间复杂度究竟是多少呢?

使用数组的时候, 因为数组随机访问的特性, 访问中间节点的时间复杂度是O(1), 二分查找的时间复杂度是O(1) + O(1) + … + O(1), 而需要访问中间节点的次数是k次, k = log2n, 所以用数组二分查找时间复杂度O(logn)。

类比到使用链表, 链表长度是n时, 访问中间节点的时间复杂度是O(n/2)=O(n), 相应的二分查找时间复杂度是 O(n/2) + O(n/4) + … + O(n/2k), k=log2n, 等比数列求和, 二分查找的时间复杂度是O(n)
我一开始是这么推断的, 但这其实是错的。你有没有发现, 之所以是等比数列是要求每次查找的目标区间都落于左半部分, 然而实际上目标有可能落于右半部分。
实际上基于链表的二分查找的时间复杂度是 O(n) + O(n) +…+ O(n), k = log2n, 最终时间复杂度是O(nlogn)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code tea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值