【算法】二分算法——x的平方根

简介: 【算法】二分算法——x的平方根

本节博客使用“二分边界算法”对“x的平方根”这一题目进行求解,有需要借鉴即可。


1.题目

题目链接:LINK

2.暴力求解

暴力求解思路:

这个题目可以用暴力求解来做,无非是从0到x的平方挨个试一下,如果是>目标值,就返回前一个数字,小于目标值,测试下一个值,等于目标值就返回该值就可以了。

假设测试数字用num来表示,其平方用num^2来表示

  • num^2 > x 返回num-1
  • num^2 = x 返回num
  • num^2 < x 继续测试num+1

显然这个题目还有更优秀的方法,就是用二分算法。

不过二分算法是怎么想到的并且是怎么进行思考的呢?下面来进行细说:

3.二分算法求解

我们在暴力求解中,无非是从0^2 ,1^2 ,2^2… , x^2…所以说也可以根据是否其平凡大于还是小于等于目标值来做划分,这就满足了我们二分算法的使用前提条件:数组具有“二段性”。



那我们可以将0~x值划分为两部分:

  • n^2 <= x
  • n^2 > x

思考:为什么要将数组划分为n^2 <= x;n^2 > x。

换言之,为什么不用n^2 < x;n^2 >= x来做划分呢???


答:因为大于x的num值绝对不可能是最终返回结果,而小于x的值有可能是最终返回结果,等于x的值一定是返回结果(有可能没有这个整数值)

根据上面思想,我们可以将整个数组划分为下面这种情况:

那么,我们具体的代码逻辑也可以得出:

  • mid*mid <= x —> left = mid;
  • mid*mid > x —> right = mid - 1;

依照上面分析,我们可以写出示例代码

class Solution {
public:
    int mySqrt(int x) 
    {
        int left = 0, right = x;
        while (left < right) 
        {
            long long mid = left + (right - left + 1) / 2;
            if (mid * mid > x) 
            {
                right = mid - 1;
            } 
            else 
            {
                left = mid;
            }
        }
        return left;
      
    }
};

其中有需要代码细节,想要知道mid取值为什么是这样以及left和right的if逻辑可以点击链接:LINK

当然,上面这个代码有点小问题哈,在leetcode是过不了的:

4.取值范围细节

在做题的时候要注意读题目中的取值范围:

题目中提示说,这个x取值范围是0到int_max值,但是我们mid计算时候,用到的是long long mid = left + (right - left + 1) / 2;这个表达式会先根据left、right类型(int)生成一个临时int变量来生成结果值赋给mid,但是在计算时候,right - left + 1 = int_max + 1这样就int临时变量溢出了,自然会报错,不过只有给的x是int_max时才会出现这个错误

所以我们可以修改一下,

方法一:是把x = 0进行特殊处理,让left从1开始right - left少一个数字

比如代码:

class Solution {
public:
 int mySqrt(int x) {
 // 由于两个较⼤的数相乘可能会超过 int 最⼤范围
 // 因此⽤ long long
 long long i = 0;
 for (i = 0; i <= x; i++)
 {
 // 如果两个数相乘正好等于 x,直接返回 i
 if (i * i == x) return i;
 // 如果第⼀次出现两个数相乘⼤于 x,说明结果是前⼀个数
 if (i * i > x) return i - 1;
 }
 // 为了处理oj题需要控制所有路径都有返回值
 return -1;
 }
};

方法二:当然还可以把int left类型改为long来处理。

class Solution {
public:
    int mySqrt(int x) 
    {
        long left = 0, right = x;
        while (left < right) 
        {
            long long mid = left + (right - left + 1) / 2;
            if (mid * mid > x) 
            {
                right = mid - 1;
            } 
            else 
            {
                left = mid;
            }
        }
        return left;
      
    }
};

5.总结

说实在的掌握了二分边界算法这个题不难,但是就是我第四步那个细节问题要注意!!!我就被坑了~


EOF

相关文章
|
7月前
|
存储 算法 程序员
平方根倒数快速算法
平方根倒数快速算法
76 0
|
7月前
|
算法 Java
算法编程(三):x 的平方根
算法编程(三):x 的平方根
72 0
|
7月前
|
算法 程序员
【算法训练-二分查找 四】【模拟二分】X的平方根
【算法训练-二分查找 四】【模拟二分】X的平方根
43 0
|
算法
【算法专题突破】二分查找 - x 的平方根(18)
【算法专题突破】二分查找 - x 的平方根(18)
75 0
|
算法 索引
【算法挨揍日记】day09——35. 搜索插入位置、69. x 的平方根
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
85 0
|
4月前
|
算法 Java 索引
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
39 0
|
6月前
|
算法 Java Go
【经典算法】LeetCode 69. x 的平方根(Java/C/Python3/Golang实现含注释说明,Easy)
【经典算法】LeetCode 69. x 的平方根(Java/C/Python3/Golang实现含注释说明,Easy)
50 1
|
6月前
|
算法
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
|
7月前
|
算法 前端开发
前端算法-x 的平方根
前端算法-x 的平方根
|
算法 Python
python与算法:两种计算平方根的算法的开销
python与算法:两种计算平方根的算法的开销
168 0
python与算法:两种计算平方根的算法的开销
下一篇
DataWorks