回来刷专题了
思路
套的二分查找,[0,x]查找mid,如果
- m i d 2 < = x mid^{2}<=x mid2<=x并且 ( m i d + 1 ) 2 > x (mid+1)^{2}>x (mid+1)2>x,返回mid
-
m
i
d
2
<
x
mid^{2}<x
mid2<x并且
(
m
i
d
+
1
)
2
<
=
x
(mid+1)^{2}<=x
(mid+1)2<=x
这里要分情况讨论,
如果 ( m i d + 1 ) 2 = x (mid+1)^{2}=x (mid+1)2=x,说明mid+1是要找的值,否则说明区间找小了,要往大了找,将left改成mid+1,区间变成[mid+1,left] -
m
i
d
2
>
x
mid^{2}>x
mid2>x
这种情况比较好说就是直接找大了,可以不考虑mid+1,因为更大了,直接往小了再找,right改成mid-1,区间变成[mid+1,right]
代码实现
private static int mySqrt(int x) {
long s=(long)x;//第一次提交发现会有越界异常,改成long了
long left=0;
long right=x;
while (left<=right){
long mid =left+(right-left)/2;
if ((mid*mid<=x)&&((mid+1)*(mid+1)>x))//憨憨直接考虑小数了,mid平方<=目标值
//或者mid+1方>目标值,就返回这个值
return (int)mid;
else if ((mid*mid<x)&&((mid+1)*(mid+1)<=x)){
if ((mid+1)*(mid+1)==x)//如果mid比目标值小但是+1正好等于目标
return (int)mid+1;//返回mid+1
left=mid+1;//不然就是区间小了,向右在找
}
else if (mid*mid>x){//大了就好说了,直接改小区间,向左边找
right=mid-1;
}
}
return -1;
}
优化
看了大佬的代码之后发现自己写的有点垃圾
- 区间优化
整型int的最大值是 2 32 − 1 2^{32} - 1 232−1(说明不会取到任何超过这个数的值),对它开平方约等于46340,任何大于这个数的整数的平方都会越界,所以我们要做好约束。 - 这个题就是一个找最右边的满足条件的值
简单抽象一下,nums数组就是 [0,1,2,3,4,…,x] target 就是 x 的平方根。以题目的 8 为例,我们 先不考虑结果只保留整数的部分最后再将小数部分去掉即可。·这么来看,2,…,2.82841,2.82842,… 都是符合的。由于需要返回不带小数的,那不就是返回 最左边的满足条件的值 么?但是这种算法比较复杂,原因在于计算误差,比如题目限定了 1 0 − 5 10 ^{-5} 10−5 以内的误差都可以,那么是可以的。
仍然以 8 为例, 我们想要在 1,2,3,4,5… (注意我这里不考虑小数了)找满足条件的 ans,使得 a n s 2 ans ^{ 2} ans2 刚好小于等于 8,也就是找所有满足 a n s 2 ans ^{ 2} ans2 <= 8 的最大值,也就是 找最右边的满足条件的值 ,这里的条件就是 <= 8。
大佬代码
class Solution {
public int mySqrt(int x) {
if(x==1)
return 1;
int left=0;
int right=46340;
while(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;
}
}
return right;
}
}