前言:
大家好,今天是LeetCode每日一题的第五天,给大家分享的是 寻找数组的中心下标,难度系数两颗星!废话不多数,先上题目!
1.1 题目要求
题目类型:x的平方根
题目要求:在不使用sqrt(x)函数的情况下, 得到x的平方根的整数部分
特别提醒:Java中的sqrt()函数用于求平方根
重点考查: 二分法、牛顿迭代
1.2 解题方法
1.2.1 二分法查找
1.解题思路
二分法查找在暴力算法的基础上进行改进得到的,所有我们需要首先了解一下暴力算法的思路
暴力算法:
由题意知, x的平方根应该在2到x-1之间(即满足 2 < x的平方根 < x-1);假设遍历到了第i个数, 满足 i < x的平方根, 左右两边同时求平方, 即转换为 i * i < x, 并且同时满足 i+1 > x的平方根, 左右两边同时求平方, 即转换为 (i+1) * (i+1) > x;
因此我们只需判断 i * i 和 (i+1) * (i+1) 哪个更接近 x值即可, 更接近前者, 那么x的平方根整数部分就为 i; 否则为i+1;
二分法查找:
设置两个左右指针left和right
left -> <-right
[2,3,4,…,x-1]
到某一时刻, 左右指针会重合, 该位置为中间值, 此时循环结束
left ->mid<-right
[2,3,4,…,x-1]
2.代码实现
- 测试代码
package com.kuang.leetcode5;
/**
* @ClassName SqrtX
* @Description x的平方根
* @Author 狂奔の蜗牛rz
* @Date 2021/8/23
*/
public class SqrtX {
//主方法测试
public static void main(String[] args) {
//使用二分查找法获取x平方根的整数部分值
//输入: 24 预测结果: 4
System.out.println("使用二分查找, x的平方根整数部分为:"+binarySearch(24)); // 真实结果: 4
}
/**
* 使用二分查找x的平方根整数部分
* @param x 求平方根的x
* @return x的平方根整数部分
*/
public static int binarySearch(int x) {
/**
* index为x平方根的整数部分值(-1表示该值不存在),
* left为左指针(从左侧开始移动, 因此初值为左侧边界起始值0),
* right为右指针(从右侧开始移动, 因此初值为右侧边界值x)
*/
int index = -1, left = 0, right = x;
//while循环的执行条件为left(左指针)值是否小于等于right(右指针)(即左指针在右指针左侧, 直至两者重合)
while(left <= right) {
//mid中心值
int mid = left + (right-left)/2;
/**
* 为什么mid = left + (right-left)/2 ?
* 原因如下:
* 初始状态:
* 0(left初值) x(right初值)
* ------------------>
* left -> <- right
*
* 左右指针移动后:
* ------|-----|----|---->
* left mid right
* |<-------->|
* right-left
* |<--->|
*
* mid值为:
* ------|-----|----|---->
* left mid right
* |<--->|<--->|
* left + (right-left)/2 = mid
*/
//判断mid(中心值)是否小于等于x的平方根(这里使用mid*mid<=x, 等同于mid(中心值)小于等于x的平方根)
if(mid * mid <= x) {
//若mid(中心值)小于等于x的平方根, 则将mid赋值给index(平方根整数部分)
index = mid;
//然后left(左指针)值加1(即左指针向右移动一位)
left = mid + 1;
} else {
//若mid(中心值)小于等于x的平方根, 则right(右指针)值加1(即右指针向左移动一位)
right = mid - 1;
}
}
//最后将index(x的平方根整数部分)返回
return index;
}
}
- 测试结果
结果:测试结果与预测一致!
1.2.2 牛顿迭代法
1.解题思路
存在已知数x,其值为整数i的平方,即i * i = x ,转化一下为i/n = n, 即i = x的平方根
例如x为12, 12的一对组合因子为 2 * 6, 即 2 * 6 = 根号12 * 根号12, 让2和6取平均值, 即 (2+6)/2= 8/2 =4, 而这一对组合因子都求平方后, 即2 * 2 = 4, 6 * 6 = 36;4求平方后为16(4 * 4), 而x值为12, 4 < 12 < 16 < 36, 16比4和36都要更接近12;
根据上面可以推出公式: (2+6)/2 => (12/6 + 6) => (x/i + i)/2
- 因此只需判断 x/i = i 等式是否成立, 然后求n的值即可;
- 求出n值后, 再代入到(x/i + i)/2中得出的结果便是x的平方根整数部分
- 如果等式一直不成立, 就一直递归(x/i + i)/2, 直到等式成立
2.代码实现
- 测试代码
package com.kuang.leetcode5;
/**
* @ClassName SqrtX
* @Description x的平方根
* @Author 狂奔の蜗牛rz
* @Date 2021/8/23
*/
public class SqrtX {
//主方法测试
public static void main(String[] args) {
//输入: 24 预测结果: 4
System.out.println("使用牛顿迭代, x的平方根整数部分为:"+newton(24)); //测试结果: 4
}
/**
* 使用牛顿迭代法获取x的平方根整数部分
* @param x 求平方根的x
* @return 平方根x的整数部分
*/
public static int newton(int x) {
//判断x是否等于0
if(x == 0) {
//若x等于0, 返回值为0
return 0;
}
//否则将sqrt方法的结果(该结果为x的平方根整数部分)进行返回
return (int)sqrt(x,x);
}
/**
求x的平方根整数部分
* @param i 被x取整的数
* @param x 求平方根的x
* @return
*/
public static double sqrt(double i, int x) {
/**
* x的平方根整数部分值为(x/i + i)/2,
* 最终需要将这个结果返回, 将其存入到res变量中
*/
double res = (i + x/i)/2;
//判断res(返回值)是否与i值相等(在不断递归的过程中res和i会越来越接近)
if(res == i) {
//将i值返回
return i;
} else {
//若res返回值不等于i, 继续调用当前方法(直至res和i值相等)进行递归
return sqrt(res, x);
}
}
}
- 测试结果
结果:测试结果与预测一致!
好了,今天LeetCode每日一题—x的平方根到这里就结束了,欢迎大家学习和讨论,点赞和收藏!
参考视频链接:https://www.bilibili.com/video/BV1Ey4y1x7J3 (国内算法宝典-LeetCode算法50讲)