• 【算法】二分查找


    二分查找思想经常会出现在一些查找的问题中,比如我们现在有1000W个整形数据,每个数据占8个字节,现在有一台内存100MB的电脑,如何设计数组结构和算法快速查找某个整数出现再这1000W个数据中呢。

    这个问题并不难,我们的内存限制时100MB,每个数据时8字节,将所有的数据存储在数组中内存占用80MB,可以使用不需要存储额外信息的数组存储在内存中,使用原地排序的算法如快排进行排序,最后用二分方法查找该数。

    二分查找针对的时一个有序的数据集合,查找的思想类似与分治思想,每次都通过和区间的中间元素进行对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0。

    二分查找时一种非常高效的查找算法,其平均时间复杂度为 O(logn) 。我们假设数据大小为 n,每次查找以后数据都会缩小为原来为原来的一半,最坏的情况下,知道查找区间被缩小为空才停止。

    当 n/(2**k) = 1时, k 的值就是总共缩小的次数,经过 k 次区间缩小操作,时间复杂度就是 O(k) ,k = (log2)n,所以时间复杂度就是 O(logn)。对数时间复杂度是一种非常高效的时间复杂度,有的时候甚至比 O(1) 还要高效。

    def binary_search(li:list,n:int)->bool:
        if not li:
            return False
        low,high = 0,len(li)-1
        while low <= high:  #注意是 low <= high,而不是 low < high
            mid = low + (high - low)//2  #如果 low 和 high 比较大的话,low + high 俩者可能会溢出
            if n == li[mid]:
                return True
            elif n < li[mid]:
                high = mid - 1  #更新的时候不考虑把 mid 加进去,下面更新同理
            else:
                low = mid + 1
        return False

    二分查找的应用场景局限性:

    1.二分查找依赖顺序表结构,即有下标随机访问数据的数组。

    2.二分查找针对的是有序数据。这里涉及到俩点,如果我们针对的是一组静态的数据,没有频繁的插入、查找、删除,我们可以一次排序,多次二分查找。但是如果是在变化的数据集合中,依赖顺序表的二分查找就不再适用,而要考虑基于二叉树的二分查找。

    3.数据量太小或者太大也不行。如果数据量太小的话,顺序遍历就够了,数据量太大的话,由于二分查找的底层需要依赖数组这种数据结构,对内存空间连续的要求就变得很苛刻了。

    二分的变形问题

    二分查找的变形问题很多,可能不是那么好写。这里有四种常见的二分查找变形问题:

    1.查找第一个值等于给定值的元素

    2.查找最后一个值等于给定值的元素

    3.查找第一个大于等于给定值的元素

    4.查找最后一个小于等于给定值的元素

    1.2解法如下:

    li[mid] 和需要查找的 n 的大小关系有三种情况: 大于、小于、等于。以第一个问题为例,对于li[mid] > n 的情况,我们需要更新 high = mid-1;对于li[mid] < value的情况,我们需要更新 high = mid - 1;对于 li[mid] = value 的情况,有俩种处理方式。

    当 li[mid] 等于要查找的值的时候, a[mid] 就是我们要找的元素,但是此时是求解的第一个值等于给定值的元素,所以这里需要确认一下是不是第一个值等于给定值的元素。

    如果 mid 等于 0,那么这个元素已经是数组的第一个元素,那它肯定是我们要找的,如果 mid 不等于 0,但 li[mid] 的前一个元素不等于 n ,那么说明此时我们找到了第一个值等于定值的元素在 li[mid] 处。

    如果经过检查以后发现 li[mid] 前面的一个元素也等于 n,那么说明此时的 li[mid] 肯定不是我们要查找的第一个值等于定值的元素,此时我们更新 high = mid-1,因为要找的元素肯定出现在[low...mid-1]之间。

    第二个问题逆向推一下同上。

  • 相关阅读:
    Windows上使用“LogView”打开大文件
    windows CMD命令查看局域网内所有主机名及IP
    解决Sqlserver 2008 R2在创建登录名出错"此版本的 Microsoft Windows 不支持 MUST_CHANGE 选项。 (Microsoft SQL Server,错误: 15195)"
    解决 ASP.NET 编辑错误"CS0006: 未能找到元数据文件C:WINDOWSassemblyGAC_32System.EnterpriseServices2.0.0.0__b03f5f7f11d50a3aSystem.EnterpriseServices.dll"
    ASP 未结束的字符串常量
    Godaddy ssl续费更新问题总结
    [转]How to query posts filtered by custom field values
    SqlServer 在查询结果中如何过滤掉重复数据
    [UE4]C++的const类成员函数
    [UE4]C++三种继承方式
  • 原文地址:https://www.cnblogs.com/guangluwutu/p/11820632.html
Copyright © 2020-2023  润新知