LeeCode:X的平方根 + 有效的完全平方数(二分查找进阶)

 x的平方根

题目:x的平方根给你一个非负整数 x ,计算并返回 x 的 算术平方根 ,由于返回类型是整型,结果只保留整数部分小数部分将被舍去,要求不允许使用任何内置指数函数和运算符

题目链接:力扣

思想(二分查找):

1. 二分查找的mid只会出现三种情况:

  • 1.mid的值的平方刚好等于x,此时这个值刚好是x的算术平方根;
  • 2.mid的值的平方大于x,此时这个值肯定不可能是x的算术平方根;
  • 3.mid的值的平方小于x,此时整个值可能是x的算术平方根(因为实际的平方根可能是小数,但是这里只保留整数部分,小数部分舍弃).

2.定义一个pos变量,每进行一次二分查找之后需要用mid的值去更新pos.

3. 当mid的值的平方小于等于x时,需要更新pos,将mid的值赋给pos(如果刚好等于直接返回pos即可,如果是小于更新完pos之后,还需要更新left的值),当mid的值的平方大于x时,说明mid的值一定不是x的算术平方根,所以需要更新right的值继续进行二分查找!

完整代码(方法一):

class Solution {
    public int mySqrt(int x) {
       int left = 0;
       int right = x;
       int pos = -1;//用来存储mid更新之前的下标 即算术平方根
       while(left <= right) {
           int mid = left + (right - left) / 2;
           if((long)mid * mid <= x) {
               //这里需要注意mid和mid的乘积可能会存在数据溢出的情况,所以需要进行强转
               //将int类型的数据强转成long类型
               pos = mid;
               left = mid + 1;
           } else {
               right = mid - 1;
           }
       }
       return pos;
}

 缺陷上述代码有一个不好的地方就是mid与mid的乘积可能超出int类型所要表示的范围,在和目标元素x比较的时候可能发生溢出的情况,所以这里保险起见,需要强转成long类型的数据!

方法二:

方法二针对方法一的缺陷进行了优化,既然mid和mid的乘积容易发生变化数据溢出的情况,那么这里直接将乘法改成除法(修改判断的条件),但是注意除法的被除数不能为0,所以需要对特殊数据0进行单独判断;

class Solution {
    public int mySqrt(int x) {
        //使用 / 可以避免mid*mid越界
        //需要对特殊数字0进行单独判断
        if(x == 0) {
            return 0;
        }
        int left = 1;
        int right = x;
        int pos = -1;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(mid <= x/mid) {
                pos = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return pos;
    }
}

有效的完全平方数

题目:给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false ;完全平方数 是一个可以写成某个整数的平方的整数;换句话说,它可以写成某个整数和自身的乘积;不能使用任何内置的库函数,如  sqrt 。

题目链接:力扣

思想:

这题可以基于上面求x的算术平方根的思想,使用二分查找,可能出现如下三种情况:

1.mid的值的平方等于num,此时num是一个完全平方数;

2.mid的值的平方小于num,需要继续对区间【mid+1,right】进行二分查找;

3.mid的值的平方大于num,需要继续对区间【left,mid-1】进行二分查找.

完全代码如下(法一):

class Solution {
    public boolean isPerfectSquare(int num) {
        int left = 0;
        int right = num;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if((long) mid * mid < num) {
                left = mid + 1;
            } else if((long) mid * mid > num) {
                right = mid - 1;
            } else {
                return true;
            }
        }
        return false;
}

缺陷上述代码有一个不好的地方就是mid与mid的乘积可能超出int类型所要表示的范围,在和目标元素x比较的时候可能发生溢出的情况,所以这里保险起见,需要强转成long类型的数据!

法二:

方法二针对方法一的缺陷进行了优化,既然mid和mid的乘积容易发生变化数据溢出的情况,那么这里直接将乘法改成除法(修改判断的条件),但是注意除法的被除数不能为0,所以需要对特殊数据0进行单独判断;

class Solution {
    public boolean isPerfectSquare(int num) {
        //判断特殊数字
        if(num == 0) {
            return true;
        }

        //对于其余数字进行判断
        int left = 1;
        int right = num;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(mid < (num*1.0/mid)) {
                left = mid + 1;
            } else if(mid > (num*1.0/mid)) {
                right = mid - 1;
            } else {
                return true;
            }
        }
        return false;
    }
}

你可能感兴趣的:(算法,java,数据结构)