探秘二分查找中的数学奇迹:如何手动求解整数x的平方根

news2024/11/24 17:00:10

在这里插入图片描述

本篇博客会讲解力扣“69. x 的平方根”这道题的解题思路。这是题目链接。

大家先来审下题:
在这里插入图片描述
以及示例:
在这里插入图片描述
还有提示:
在这里插入图片描述
本题常规的思路有:暴力查找、转换成指数和对数、二分查找、牛顿迭代。

转换成指数和对数的方法非常简单:x0.5=ln(exp(x0.5))=ln(0.5exp(x)),直接调用对应的库函数求解即可。牛顿迭代是我在“数值方法”这门专业课学到的方法(博主是学数学的),讲解起来可能有点复杂,这里就不讲解了。

我还是更加推荐查找的思路。暴力查找过于直接,效率太低,所以采取的是优化的方案:二分查找。二分查找思路简单,没有牛顿迭代这种非常复杂的数学推导,同时不用调用数学库函数,效率也还行,为O(logN)。

首先需要把这道题转换一下:在[0,x]中查找一个最大的数n,使得n*n<=x即可。所以直接手撕二分查找:

int mySqrt(int x){
	// [0,x]二分查找
    int left = 0;
    int right = x;
    while (left <= right)
    {
        // 求left和right的平均数
        int mid = left + (right-left) / 2;
        if (mid*mid > x)
        {

        }
        else if (mid*mid < x)
        {

        }
        else
        {
            // 找到了
            return mid;
        }
    }
}

大家很容易写出来上面的代码。接下来需要分析一下:如果mid*mid > x,说明mid已经比x的算术平方根大了,此时应该往“小的方向”找,也就是到区间左半边找,反之同理。

int mySqrt(int x){
	// [0,x]二分查找
    int left = 0;
    int right = x;
    while (left <= right)
    {
        // 求left和right的平均数
        int mid = left + (right-left) / 2;
        if (mid*mid > x)
        {
            // 到左边找
            right = mid - 1;
        }
        else if (mid*mid < x)
        {
            // 到右边找
            left = mid + 1;
        }
        else
        {
            // 找到了
            return mid;
        }
    }
}

最后一个问题:如果“找不到”返回什么?一般来说,进行二分查找时,如果出了循环还没找到,此时就找不到了。但是这道题其实只是“类二分查找”,也就是说,找不到其实也是很正常的,因为有些数的算术平方根是小数。本质上你要找的是一个小数,但是却在一堆整数中找,当然找不到喽。举个例子:你要找的是7.5,mid就会逐渐逼近7.5,最后一次mid==7时,会执行left=mid+1,此时left就会变成8,并且left不会再变了,因为mid*mid<x已经没有机会了。所以,我们想返回的是7,最后left就一定是8,就应该返回left-1。

int mySqrt(int x){
	// [0,x]二分查找
    int left = 0;
    int right = x;
    while (left <= right)
    {
        // 求left和right的平均数
        int mid = left + (right-left) / 2;
        if (mid*mid > x)
        {
            // 到左边找
            right = mid - 1;
        }
        else if (mid*mid < x)
        {
            // 到右边找
            left = mid + 1;
        }
        else
        {
            // 找到了
            return mid;
        }
    }

    // left会跑到mid的右边,因为答案是mid的时候,mid的平方小于x
    return left - 1;
}

但这样过不了:
在这里插入图片描述
意料之中。因为这个数太大了,int存不下。这时,最简单的方法是把类型都改成long long,就可以了。

int mySqrt(int x){
	// [0,x]二分查找
    long long left = 0;
    long long right = x;
    while (left <= right)
    {
        // 求left和right的平均数
        long long mid = left + (right-left) / 2;
        if (mid*mid > x)
        {
            // 到左边找
            right = mid - 1;
        }
        else if (mid*mid < x)
        {
            // 到右边找
            left = mid + 1;
        }
        else
        {
            // 找到了
            return mid;
        }
    }

    // left会跑到mid的右边,因为答案是mid的时候,mid的平方小于x
    return left - 1;
}

不过毕竟类型不匹配,建议加上强制类型转换。

int mySqrt(int x){
    // [0,x]二分查找
    long long left = 0;
    long long right = x;
    while (left <= right)
    {
        // 求left和right的平均数
        long long mid = left + (right-left) / 2;
        if (mid*mid > (long long)x)
        {
            // 到左边找
            right = mid - 1;
        }
        else if (mid*mid < (long long)x)
        {
            // 到右边找
            left = mid + 1;
        }
        else
        {
            // 找到了
            return mid;
        }
    }

    // left会跑到mid的右边,因为答案是mid的时候,mid的平方小于x
    return (int)(left - 1);
}

在这里插入图片描述

这样就过了。

总结

  1. 掌握二分查找,这是有序数组查找最好的方式。
  2. 明白最后要返回啥,也就是left-1代表了啥。

感谢大家的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/499695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

接口自动化测试框架9项必备功能有哪些?你一定不知道

当你准备使用一个接口测试框架或者自造轮子的时候&#xff0c;或许你需要先了解下一个接口自动化测试框架必须具备什么功能。 一、校验   这个很好了解&#xff0c;如果没有校验&#xff0c;单纯的执行接口的话&#xff0c;那就谈不上测试了。所以支持对返回值校验是一个必须…

[Golang] 爬虫实战-获取动态页面数据-获取校招信息

&#x1f61a;一个不甘平凡的普通人&#xff0c;致力于为Golang社区和算法学习做出贡献&#xff0c;期待您的关注和认可&#xff0c;陪您一起学习打卡&#xff01;&#xff01;&#xff01;&#x1f618;&#x1f618;&#x1f618; &#x1f917;专栏&#xff1a;算法学习 &am…

Solr(1):Solr概述

1 概述 Solr 是一个基于 Apache Lucene 之上的搜索服务器&#xff0c;它是一个开源的、基于 Java 的信息检索库。它旨在驱动功能强大的文档检索应用程序 - 无论您需要根据用户的查询将数据服务到何处&#xff0c;Solr 都可以为您服务。Solr与应用程序的集成以为您服务。 下面…

es 7.x 通过DSL语句添加doc数据

一 在es中doc数据的crud操作 1.1 说明 本案例操作 接上一篇的基础上进行操作。 1.2 添加doc 方式为post http://localhost:9200/order_item/_doc 添加文档数据 必须是post提交&#xff0c;不能是put 1.3 查看文档数据 http://localhost:9200/order_item/_doc/_searc…

118-Linux_数据库_索引

文章目录 一.索引是什么?二.索引为什么选择b树三.测试索引1.在mysql中创建数据库 test_indexdb2.在test_indexdb中创建表 test_index3.运行程序向表中插入1万条数据&#xff0c;都是字符串4. 查询验证 一.索引是什么? 索引是一种特殊的文件&#xff0c;它包含着对数据表里所…

浅谈osgEarth操控器类的createLocalCoordFrame函数如何将局部坐标系的点转为世界坐标系下的Martix(ENU坐标)

在osgEarth操控器类的EarthManipulator中的如下函数&#xff1a; void EarthManipulator::setLookAt(const osg::Vec3d& center,double azim,double pitch,double range,const osg::Vec3d& posOffset) {setCenter( center );.... //…

二、PEMFC基础之电化学与反应动力学

二、PEMFC基础之电化学与反应动力学 1.电流、电流密度2.反应速率常数3.交换电流密度4.电化学动力学奠基石B-V方程5.活化损失计算Tafel公式6.计算案例 1.电流、电流密度 由法拉第定律 i d Q d t n F d N d t i\frac{dQ}{dt}\frac{nFdN}{dt} idtdQ​dtnFdN​ j i A j\frac{…

查询缓存实现、缓存更新策略选择、解决缓存穿透缓存雪崩缓存击穿问题

文章目录 1 什么是缓存?1.1 为什么要使用缓存1.2 如何使用缓存 2 给商户信息查询业务添加缓存2.1 缓存模型和思路2.2 代码如下 3 缓存更新策略3.1 数据库缓存不一致解决方案&#xff1a;3.2 数据库和缓存不一致采用什么方案3.3 删除缓存还是更新缓存&#xff1f;3.4 如何保证缓…

MySQL --- DQL

使用DDL语句来操作数据库以及表结构&#xff08;数据库设计&#xff09;使用DML语句来完成数据库中数据的增、删、改操作&#xff08;数据库操作&#xff09; 学习数据库操作方面的内容&#xff1a;查询&#xff08;DQL语句&#xff09;。 查询操作我们分为两部分学习&#…

chatgpt如何接入本地知识库?我们来看看EMNLP 2022 INFO是如何融入本地知识的

一、概述 title&#xff1a;You Truly Understand What I Need : Intellectual and Friendly Dialogue Agents grounding Knowledge and Persona 论文地址&#xff1a;You Truly Understand What I Need : Intellectual and Friendly Dialog Agents grounding Persona and Know…

基于S/Key协议的身份认证系统设计与实现【python】

实验内容 1 、 身份认证系统设计 设计身份认证系统的功能、主要界面、主要软件模块&#xff0c;以及采用的认证技术路线和方法。 2 、 编程实现所设计的身份认证系统 在C、Python或Java程序设计环境下&#xff0c;编程实现基于S/Key协议的身份认证系统。要求实现的身份认证…

计算机中丢失msvcp140.dll无法启动此程序怎么办?msvcp140.dll在哪里

电脑系统中的 msvcp140.dll 文件是 Microsoft Visual C Redistributable 组件的一部分&#xff0c;它们提供了许多在 Windows 操作系统中运行的应用程序所需的重要函数和库。如果丢失了 msvcp140.dll 文件&#xff0c;你可能会遇到多种错误&#xff0c;比如无法运行应用程序、系…

【RabbitMQ】安装及六种模式

文章目录 安装rabbitmq镜像访问容器内部15672端口映射到外面的端口地址RabbitMQ六种模式Hello world模式Work queues模式Publish/Subscribe模式交换机fanout类型 Routing模式Topics模式RPC模式 rabbitmq&#xff1a;0->1的学习 学习文档&#xff1a;https://www.cnblogs.com…

Java集合之双列集合

双列集合特点 双列集合一次需要添加一对数据&#xff0c;分别是键和值键不能重复&#xff0c;值可以重复键和值是一一对应的&#xff0c;每一个键只能找到自己对应的值键 值这个整体称为“键值对”或者“键值对对象”&#xff0c;Java中叫“Entry对象” 双列集合的体系结构 Ma…

linux系统systemd初始化进程

前言&#xff1a;目前绝大多数服务器系统以及从RHEL6换成RHEL7了&#xff0c;以前习惯使用service来管理系统服务的&#xff0c;那么现在就比较郁闷了&#xff0c;RHEL7系统中使用systemctl命令来管理服务。 systemctl启动、重启、停止、查看状态命令&#xff1a; systemctl …

算法竞赛字符串篇之C++中string的成员函数

2023年5月7日&#xff0c;周日中午&#xff1a; 今天决定从字符串这个知识点开始学起&#xff0c;记录一下我今天的字符串学习。 不定期更新。 相关的英文文档&#xff1a; https://cplusplus.com/reference/string/string/ 容量方面的成员函数&#xff1a; empty&#xff…

基于AT89C51单片机的电子闹钟设计与仿真

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87761718?spm=1001.2014.3001.5503 源码获取 主要内容: 基于51单片机设计一个电子闹钟,至少具有以下功能:时间的设定、时间的调整、闹钟的设定、温度的设定。 基本要求:…

排队论_M/M/1/inf/inf 问题

例:某修理店只有一一个修理工人&#xff0c;来修理的顾客到达数服从泊松分布&#xff0c;平均每小时4人;修理时间服从负指数分布&#xff0c;平均需6分钟。求: (1)修理店空闲的概率; (2)店内有3个顾客的概率; (3)店内至少有1个顾客的概率; (4)店内顾客的平均数; (5)顾客在店内的…

显著性检测:从传统方法到深度学习网络的演进与挑战

显著性检测技术在计算机视觉领域中扮演着至关重要的角色&#xff0c;它是一项对图像中最显著或最有区别的视觉特征进行分析和提取的技术。显著性检测技术可以为计算机视觉任务提供帮助&#xff0c;例如图像分割、目标检测、场景理解、图像检索和人机交互等方面。 本文将从传统方…